import json from dataclasses import dataclass, field from typing import Any import valkey from pydantic import BaseModel # @dataclass(kw_only=True) class Algo_Config_Overrides(BaseModel): Allow_Ordering_Aster: bool Allow_Ordering_Extend: bool Allow_Symbol_Change: bool Flatten_Open_Positions: bool Flip_Side_For_Testing: bool # @dataclass(kw_only=True) class Algo_Config_Config(BaseModel): Loop_Sleep_Sec: int Max_Order_Over_Notional_Ratio: float Max_Target_Notional: float Min_Time_To_Funding_Minutes: int Min_Fund_Rate_Pct_To_Trade: float Price_Worsener_Aster: float Price_Worsener_Extend: float Switch_To_Taker_Seconds: int Target_Open_Cash_Position: int # @dataclass(kw_only=True) class Algo_Config_Logging(BaseModel): Log_Summary_Each_Loop: bool Print_Summary_Each_Loop: bool # @dataclass(kw_only=True) class Algo_Config(BaseModel): Updated_Timestamp: int Config: Algo_Config_Config Logging: Algo_Config_Logging Overrides: Algo_Config_Overrides @dataclass(kw_only=True) class Flags: LIQUIDATE_POS_AND_KILL_ALGO_FLAG: bool = False NET_FUNDING_IS_ZERO: bool = False @dataclass(kw_only=True) class Valkey_Stream: client: valkey.Valkey channel: str data: Any = None none_fill: Any = None async def update(self): r: str = self.client.get(name=self.channel) # ty:ignore[invalid-assignment] self.data = json.loads(s=r) if r is not None else self.none_fill @dataclass(kw_only=True) class Position: market: str notional: float qty: float @dataclass(kw_only=True) class Open_Positions: Valkey: Valkey_Stream Positions: list[Position] = field(default_factory = list) async def update(self) -> None: self.Valkey = await self.Valkey.update() ### Collateral ### @dataclass(kw_only=True) class Asset: symbol: str balance: float # min_order_qty: float @dataclass(kw_only=True) class Collateral: Valkey: Valkey_Stream # Last_Updated_Ts_Ms: int # Last_Pulled_Ts_Ms: int Assets: list[Asset] = field(default_factory = list) async def update(self) -> None: self.Valkey = await self.Valkey.update() ### Orders ### @dataclass(kw_only=True) class Order: symbol: str order_id: str client_order_id: str side: str order_type: str original_qty: float original_price: float order_status: str last_filled_qty: float last_filled_price: float commission: float trade_is_maker: bool @dataclass(kw_only=True) class Order_Updates: # Last_Updated_Ts_Ms: int # Last_Pulled_Ts_Ms: int Valkey: Valkey_Stream Orders: list[Order] = field(default_factory = list) async def update(self) -> None: self.Valkey = await self.Valkey.update() ### Funding Rate ### @dataclass(kw_only=True) class Funding_Rate: # Last_Updated_Ts_Ms: int # Last_Pulled_Ts_Ms: int Valkey: Valkey_Stream timestamp_arrival: int timestamp_msg: int symbol: str funding_rate: float next_funding_time_ts_ms: int mark_price: float index_price: float estimated_settle_price: float async def update(self) -> None: self.Valkey = await self.Valkey.update() ### Markets Info ### @dataclass(kw_only=True) class Market: symbol: str min_order_qty: float @dataclass(kw_only=True) class Markets_Details: Markets: list[Market] = field(default_factory=list) ### Exchanges ### @dataclass(kw_only=True) class Perpetual_Exchange: # Order_Updates: Order_Updates # Position_Updates: Open_Positions # Collateral_Updates: Collateral # Funding_Rate: Funding_Rate # Markets: Markets_Details mult: int lh_asset: str rh_asset: str symbol_asset_separator: str = '' # async def update(self): # await self.Collateral_Updates.update() # await self.Order_Updates.update() # await self.Position_Updates.update() # await self.Funding_Rate.update() def __post_init__(self) -> None: self.symbol = f'{self.lh_asset.upper()}{self.symbol_asset_separator}{self.rh_asset.upper()}' # @dataclass(kw_only=True) # class Aster(Perpetual_Exchange): # name: str = 'Aster' # lh_asset: str = 'ETH' # rh_asset: str = 'USDT' # def __post_init__(self): # super().__post_init__() # self.Order_Updates = Order_Updates(Valkey=Valkey_Stream(channel = 'fr_aster_user_balances', none_fills = [])) # self.Collateral_Updates = Collateral(Valkey=Valkey_Stream(channel = 'fr_aster_user_orders', none_fills = [])) # self.Position_Updates = Open_Positions(Valkey=Valkey_Stream(channel = 'fr_aster_user_positions', none_fills = [])) # self.Funding_Rate - Funding_Rate(Valkey=Valkey_Stream(channel = 'fund_rate_aster', none_fills = None)) # @dataclass(kw_only=True) # class Extend(Perpetual_Exchange): # name: str = 'Extended' # lh_asset: str = 'ETH' # rh_asset: str = 'USD' # symbol_asset_separator: str = '-' # def __post_init__(self): # super().__post_init__() # self.Order_Updates = Order_Updates(Valkey=Valkey_Stream(channel = 'fr_aster_user_balances', none_fills = [])) # self.Collateral_Updates = Collateral(Valkey=Valkey_Stream(channel = 'fr_aster_user_orders', none_fills = [])) # self.Position_Updates = Open_Positions(Valkey=Valkey_Stream(channel = 'fr_aster_user_positions', none_fills = [])) # self.Funding_Rate - Funding_Rate(Valkey=Valkey_Stream(channel = 'fund_rate_aster', none_fills = None))