from __future__ import annotations from functools import partial from typing import Callable, Coroutine, Dict, List from cvttpy_tools.settings.cvtt_types import JsonDictT from cvttpy_tools.app import App from cvttpy_tools.config import Config from cvttpy_tools.base import NamedObject from cvttpy_tools.config import CvttAppConfig from cvttpy_tools.logger import Log # --- from cvttpy_trading.trading.instrument import ExchangeInstrument from cvttpy_trading.trading.active_instruments import Instruments from cvttpy_trading.trading.mkt_data.md_summary import MdTradesAggregate # --- from pairs_trading.lib.pt_strategy.live.live_strategy import PtLiveStrategy # from pairs_trading.lib.pt_strategy.live.pricer_md_client import PtMktDataClient from pairs_trading.lib.pt_strategy.live.ti_sender import TradingInstructionsSender # import sys # print("PYTHONPATH directories:") # for path in sys.path: # print(path) HistMdCbT = Callable[[List[MdTradesAggregate]], Coroutine] UpdateMdCbT = Callable[[MdTradesAggregate], Coroutine] class PairsTrader(NamedObject): config_: CvttAppConfig instruments_: List[JsonDictT] live_strategy_: PtLiveStrategy # pricer_client_: PtMktDataClient def __init__(self) -> None: self.instruments_ = [] App.instance().add_cmdline_arg( "--pair", type=str, required=True, help=( "Comma-separated pair of instrument symbols" " with exchange config name" " (e.g., PAIR-BTC-USD:BNBSPOT,PAIR-ETH-USD:BNBSPOT)" ), ) App.instance().add_call(App.Stage.Config, self._on_config()) App.instance().add_call(App.Stage.Run, self.run()) async def _on_config(self) -> None: self.config_ = CvttAppConfig.instance() # ------- PARSE INSTRUMENTS ------- instr_str = App.instance().get_argument("pair", "") if not instr_str: raise ValueError("Pair is required") instr_list = instr_str.split(",") for instr in instr_list: instr_parts = instr.split(":") if len(instr_parts) != 2: raise ValueError(f"Invalid pair format: {instr}") instrument_id = instr_parts[0] exch_acct = instr_parts[1] exch_inst = Instruments.instance() self.instruments_.append({ "exch_acct": exch_acct, "instrument_id": instrument_id }) assert len(self.instruments_) == 2, "Only two instruments are supported" Log.info(f"{self.fname()} Instruments: {self.instruments_}") # ------- CREATE CVTT CLIENT ------- ti_config = self.config_.get_subconfig("ti_config", Config(json_src={})) self.ti_sender_ = TradingInstructionsSender(config=ti_config) Log.info(f"{self.fname()} TI client created: {self.ti_sender_}") # ------- CREATE STRATEGY ------- strategy_config = self.config_.get_value("strategy_config", {}) self.live_strategy_ = PtLiveStrategy( config=strategy_config, instruments=self.instruments_, pairs_trader=self ) Log.info(f"{self.fname()} Strategy created: {self.live_strategy_}") # # ------- CREATE PRICER CLIENT ------- # URGENT # pricer_config = self.config_.get_subconfig("pricer_config", {}) # self.pricer_client_ = PtMktDataClient( # live_strategy=self.live_strategy_, # pricer_config=pricer_config # ) # Log.info(f"{self.fname()} CVTT Pricer client created: {self.pricer_client_}") # ------- CREATE TRADER CLIENT ------- # URGENT # (send TradingInstructions) # ti_config = self.config_.get_subconfig("ti_config", {}) # self.ti_sender_ = TradingInstructionsSender(config=ti_config) # Log.info(f"{self.fname()} TI client created: {self.ti_sender_}") # # ------- CREATE REST SERVER ------- # for dashboard communications async def subscribe_md(self) -> None: pass # URGENT implement PairsTrader.subscribe_md() async def run(self) -> None: Log.info(f"{self.fname()} ...") pass if __name__ == "__main__": App() CvttAppConfig() PairsTrader() App.instance().run()