pairs_trading/bin/pairs_trader.py
2025-08-21 00:46:28 +00:00

106 lines
3.6 KiB
Python

from __future__ import annotations
from functools import partial
from typing import Dict, List
from cvttpy_tools.settings.cvtt_types import JsonDictT
from cvttpy_tools.tools.app import App
from cvttpy_tools.tools.base import NamedObject
from cvttpy_tools.tools.config import CvttAppConfig
from cvttpy_tools.tools.logger import Log
from pt_strategy.live.live_strategy import PtLiveStrategy
from pt_strategy.live.pricer_md_client import PtMktDataClient
from pt_strategy.live.ti_sender import TradingInstructionsSender
# import sys
# print("PYTHONPATH directories:")
# for path in sys.path:
# print(path)
# from cvtt_client.mkt_data import (CvttPricerWebSockClient,
# CvttPricesSubscription, MessageTypeT,
# SubscriptionIdT)
class PairTradingRunner(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]
exchange_config_name = instr_parts[1]
self.instruments_.append({
"exchange_config_name": exchange_config_name,
"instrument_id": instrument_id
})
assert len(self.instruments_) == 2, "Only two instruments are supported"
Log.info(f"{self.fname()} Instruments: {self.instruments_}")
# ------- CREATE TI (trading instructions) CLIENT -------
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 STRATEGY -------
strategy_config = self.config_.get_value("strategy_config", {})
self.live_strategy_ = PtLiveStrategy(
config=strategy_config,
instruments=self.instruments_,
ti_sender=self.ti_sender_
)
Log.info(f"{self.fname()} Strategy created: {self.live_strategy_}")
# ------- CREATE PRICER CLIENT -------
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_}")
async def run(self) -> None:
Log.info(f"{self.fname()} ...")
pass
if __name__ == "__main__":
App()
CvttAppConfig()
PairTradingRunner()
App.instance().run()