Allocate pnl calc subtask inside order mode machinery
							parent
							
								
									fd982df7a9
								
							
						
					
					
						commit
						423fc8332c
					
				|  | @ -41,7 +41,6 @@ from .._daemon import ( | |||
|     maybe_spawn_brokerd, | ||||
| ) | ||||
| from ..brokers import get_brokermod | ||||
| from ..calc import percent_change | ||||
| from ._axes import ( | ||||
|     DynamicDateAxis, | ||||
|     PriceAxis, | ||||
|  | @ -68,7 +67,6 @@ from ..data import maybe_open_shm_array | |||
| from ..data.feed import open_feed, Feed, install_brokerd_search | ||||
| from ..data._source import Symbol | ||||
| from ..data._sharedmem import ShmArray | ||||
| from ..data._normalize import iterticks | ||||
| from .. import brokers | ||||
| from ..log import get_logger | ||||
| from ._exec import run_qtractor | ||||
|  | @ -1841,49 +1839,14 @@ async def display_symbol_data( | |||
|             async with ( | ||||
| 
 | ||||
|                 open_order_mode( | ||||
|                     feed, | ||||
|                     chart, | ||||
|                     symbol, | ||||
|                     provider, | ||||
|                     order_mode_started | ||||
|                 ) as order_mode, | ||||
|             ): | ||||
|                 pp = order_mode.pp | ||||
|                 live = pp.live_pp | ||||
| 
 | ||||
|                 if live.size < 0: | ||||
|                     types = ('ask', 'last') | ||||
| 
 | ||||
|                 elif live.size > 0: | ||||
|                     types = ('bid', 'last') | ||||
| 
 | ||||
|                 else: | ||||
|                     raise RuntimeError('No pp?!?!') | ||||
| 
 | ||||
|                 # real-time update pnl on the  order mode | ||||
|                 async with feed.stream.subscribe() as bstream: | ||||
|                     last_tick = time.time() | ||||
|                     async for quotes in bstream: | ||||
| 
 | ||||
|                         now = time.time() | ||||
|                         period = now - last_tick | ||||
| 
 | ||||
|                         for sym, quote in quotes.items(): | ||||
| 
 | ||||
|                             for tick in iterticks(quote, types): | ||||
|                                 print(f'{1/period} Hz') | ||||
| 
 | ||||
|                                 # compute and display pnl status | ||||
|                                 order_mode.pane.pnl_label.format( | ||||
|                                     pnl=round( | ||||
|                                         live.size * percent_change( | ||||
|                                             live.avg_price, | ||||
|                                             tick['price'], | ||||
|                                         ), | ||||
|                                         ndigits=2, | ||||
|                                     ) | ||||
|                                 ) | ||||
| 
 | ||||
|                                 last_tick = time.time() | ||||
|                 await trio.sleep_forever() | ||||
| 
 | ||||
| 
 | ||||
| async def load_provider_search( | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ Chart trading, the only way to scalp. | |||
| from contextlib import asynccontextmanager | ||||
| from dataclasses import dataclass, field | ||||
| from functools import partial | ||||
| from math import copysign | ||||
| from pprint import pformat | ||||
| import time | ||||
| from typing import Optional, Dict, Callable, Any | ||||
|  | @ -32,8 +33,11 @@ import tractor | |||
| import trio | ||||
| 
 | ||||
| from .. import brokers | ||||
| from ..calc import percent_change | ||||
| from ..clearing._client import open_ems, OrderBook | ||||
| from ..data._source import Symbol | ||||
| from ..data._normalize import iterticks | ||||
| from ..data.feed import Feed | ||||
| from ..log import get_logger | ||||
| from ._editors import LineEditor, ArrowEditor | ||||
| from ._lines import order_line, LevelLine | ||||
|  | @ -466,6 +470,7 @@ class OrderMode: | |||
| @asynccontextmanager | ||||
| async def open_order_mode( | ||||
| 
 | ||||
|     feed: Feed, | ||||
|     chart: 'ChartPlotWidget',  # noqa | ||||
|     symbol: Symbol, | ||||
|     brokername: str, | ||||
|  | @ -520,7 +525,7 @@ async def open_order_mode( | |||
|         form = chart.sidepane | ||||
|         form.model = alloc | ||||
| 
 | ||||
|         pp_tracker = PositionTracker(chart) | ||||
|         pp_tracker = PositionTracker(chart, alloc) | ||||
|         pp_tracker.hide() | ||||
| 
 | ||||
|         # order pane widgets and allocation model | ||||
|  | @ -574,6 +579,35 @@ async def open_order_mode( | |||
|                 pp_tracker.update(msg, position=pp_tracker.startup_pp) | ||||
|                 pp_tracker.update(msg) | ||||
| 
 | ||||
|         live_pp = mode.pp.live_pp | ||||
|         size = live_pp.size | ||||
|         if size: | ||||
|             global _zero_pp | ||||
|             _zero_pp = False | ||||
| 
 | ||||
|             # compute and display pnl status immediately | ||||
|             mode.pane.pnl_label.format( | ||||
|                 pnl=round( | ||||
|                     copysign(1, size) * percent_change( | ||||
|                         live_pp.avg_price, | ||||
|                         # last historical close price | ||||
|                         feed.shm.array[-1][['close']][0], | ||||
|                     ), | ||||
|                     ndigits=2, | ||||
|                 ) | ||||
|             ) | ||||
| 
 | ||||
|             # spawn updater task | ||||
|             n.start_soon( | ||||
|                 display_pnl, | ||||
|                 feed, | ||||
|                 mode, | ||||
|             ) | ||||
| 
 | ||||
|         else: | ||||
|             # set 0% pnl | ||||
|             mode.pane.pnl_label.format(pnl=0) | ||||
| 
 | ||||
|         # make fill bar and positioning snapshot | ||||
|         order_pane.init_status_ui() | ||||
| 
 | ||||
|  | @ -601,16 +635,83 @@ async def open_order_mode( | |||
| 
 | ||||
|             n.start_soon( | ||||
|                 process_trades_and_update_ui, | ||||
|                 n, | ||||
|                 feed, | ||||
|                 mode, | ||||
|                 trades_stream, | ||||
|                 book, | ||||
|             ) | ||||
|             yield mode | ||||
|             # await trio.sleep_forever() | ||||
| 
 | ||||
| 
 | ||||
| _zero_pp: bool = True | ||||
| 
 | ||||
| 
 | ||||
| async def display_pnl( | ||||
|     feed: Feed, | ||||
|     order_mode: OrderMode, | ||||
| ) -> None: | ||||
|     '''Real-time display the current pp's PnL in the appropriate label. | ||||
| 
 | ||||
|     Error if this task is spawned where there is a net-zero pp. | ||||
| 
 | ||||
|     ''' | ||||
|     global _zero_pp | ||||
|     assert not _zero_pp | ||||
| 
 | ||||
|     pp = order_mode.pp | ||||
|     live = pp.live_pp | ||||
| 
 | ||||
|     if live.size < 0: | ||||
|         types = ('ask', 'last', 'last', 'utrade') | ||||
| 
 | ||||
|     elif live.size > 0: | ||||
|         types = ('bid', 'last', 'last', 'utrade') | ||||
| 
 | ||||
|     else: | ||||
|         raise RuntimeError('No pp?!?!') | ||||
| 
 | ||||
|     # real-time update pnl on the status pane | ||||
|     async with feed.stream.subscribe() as bstream: | ||||
|         last_tick = time.time() | ||||
|         async for quotes in bstream: | ||||
| 
 | ||||
|             now = time.time() | ||||
|             period = now - last_tick | ||||
| 
 | ||||
|             for sym, quote in quotes.items(): | ||||
| 
 | ||||
|                 for tick in iterticks(quote, types): | ||||
|                     print(f'{1/period} Hz') | ||||
| 
 | ||||
|                     size = live.size | ||||
| 
 | ||||
|                     if size == 0: | ||||
|                         # terminate this update task since we're | ||||
|                         # no longer in a pp | ||||
|                         _zero_pp = True | ||||
|                         order_mode.pane.pnl_label.format(pnl=0) | ||||
|                         return | ||||
| 
 | ||||
|                     else: | ||||
|                         # compute and display pnl status | ||||
|                         order_mode.pane.pnl_label.format( | ||||
|                             pnl=round( | ||||
|                                 copysign(1, size) * percent_change( | ||||
|                                     live.avg_price, | ||||
|                                     tick['price'], | ||||
|                                 ), | ||||
|                                 ndigits=2, | ||||
|                             ) | ||||
|                         ) | ||||
| 
 | ||||
|                     last_tick = time.time() | ||||
| 
 | ||||
| 
 | ||||
| async def process_trades_and_update_ui( | ||||
| 
 | ||||
|     n: trio.Nursery, | ||||
|     feed: Feed, | ||||
|     mode: OrderMode, | ||||
|     trades_stream: tractor.MsgStream, | ||||
|     book: OrderBook, | ||||
|  | @ -619,6 +720,7 @@ async def process_trades_and_update_ui( | |||
| 
 | ||||
|     get_index = mode.chart.get_index | ||||
|     tracker = mode.pp | ||||
|     global _zero_pp | ||||
| 
 | ||||
|     # this is where we receive **back** messages | ||||
|     # about executions **from** the EMS actor | ||||
|  | @ -640,6 +742,13 @@ async def process_trades_and_update_ui( | |||
|                 # update order pane widgets | ||||
|                 mode.pane.update_status_ui() | ||||
| 
 | ||||
|             if mode.pp.live_pp.size and _zero_pp: | ||||
|                 _zero_pp = False | ||||
|                 n.start_soon( | ||||
|                     display_pnl, | ||||
|                     feed, | ||||
|                     mode, | ||||
|                 ) | ||||
|             # short circuit to next msg to avoid | ||||
|             # uncessary msg content lookups | ||||
|             continue | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue