Files
Funding_Rate/modules/structs.py

302 lines
7.8 KiB
Python
Raw Normal View History

2026-04-25 23:43:28 +00:00
import json
from dataclasses import dataclass, field
from typing import Any
import valkey
from pydantic import BaseModel
2026-04-25 23:43:28 +00:00
2026-05-05 16:38:45 +00:00
from sqlalchemy.util.typing import Self
from collections.abc import Sequence, Callable
def ret_true():
return True
class Locked_Value(Sequence):
def __init__(self, initial_value: Any = None, unlock_func: Callable=ret_true):
self._value: Any = initial_value
self._unlock_func: Callable = unlock_func
self._is_locked: bool = True
def __repr__(self):
return str((self._value, self._is_locked, self._unlock_func))
def __len__(self):
return len((self._value, self._is_locked, self._unlock_func))
def __getitem__(self, index):
return (self._value, self._is_locked, self._unlock_func)[index]
def __str__(self):
return str((self._value))
def unlock(self) -> Self:
if self._unlock_func():
self._is_locked = False
return self
def lock(self) -> Self:
self._is_locked = True
return self
@property
def is_locked(self):
return self._is_locked
@property
def is_unlocked(self):
return not(self._is_locked)
@property
def value(self):
return self._value
@value.setter
def value(self, v):
if not(self._is_locked):
self._value = v
else:
raise ValueError(f'Failed to set value, item is locked: {str(self.__repr__)}')
class Current_Previous_Value:
def __init__(self, value: Any = None, previous_value: Any = None):
self._value: Any = value
self._previous_value: Any = previous_value
def __repr__(self):
return str((self._value, self._previous_value))
def __len__(self):
return len((self._value, self._previous_value))
def __getitem__(self, index):
return (self._value, self._previous_value)[index]
def __str__(self):
return str(self._value)
@property
def value(self):
return self._value
@property
def previous_value(self):
return self._previous_value
@value.setter
def value(self, v):
self._previous_value = self._value
self._value = v
# @dataclass(kw_only=True)
class Algo_Config_Overrides(BaseModel):
2026-04-25 23:43:28 +00:00
Allow_Ordering_Aster: bool
Allow_Ordering_Extend: bool
2026-04-30 04:32:49 +00:00
Allow_Symbol_Change: bool
Flatten_Open_Positions: bool
Flatten_Open_Positions_Opportunistic: bool
Flip_Side_For_Testing: bool
2026-04-30 04:32:49 +00:00
# @dataclass(kw_only=True)
class Algo_Config_Config(BaseModel):
2026-04-25 23:43:28 +00:00
Loop_Sleep_Sec: int
Max_Order_Over_Notional_Ratio: float
2026-04-25 23:43:28 +00:00
Max_Target_Notional: float
Min_Time_To_Funding_Minutes: int
2026-04-28 15:02:32 +00:00
Min_Fund_Rate_Pct_To_Trade: float
Price_Worsener_Aster: int
Price_Worsener_Extend: int
Switch_To_Taker_Seconds: int
2026-04-25 23:43:28 +00:00
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
2026-04-25 23:43:28 +00:00
@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):
2026-04-30 04:32:49 +00:00
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
2026-04-25 23:43:28 +00:00
@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
lh_asset: str
rh_asset: str
symbol: str = ''
2026-04-25 23:43:28 +00:00
symbol_asset_separator: str = ''
mult: int
initial_funding_rate: float = 0
min_price: float = 0
min_order_size: float = 0
2026-05-04 18:04:45 +00:00
min_lot_size: float = 0
min_notional: float = 0
2026-05-05 16:38:45 +00:00
buy_ratio: float = 0
notional_obj: dict = field(default_factory=dict)
notional_position: float = 0
unrealized_pnl: float = 0
2026-04-25 23:43:28 +00:00
2026-04-30 04:32:49 +00:00
# async def update(self):
# await self.Collateral_Updates.update()
# await self.Order_Updates.update()
# await self.Position_Updates.update()
# await self.Funding_Rate.update()
2026-04-25 23:43:28 +00:00
def __post_init__(self) -> None:
self.symbol = f'{self.lh_asset.upper()}{self.symbol_asset_separator}{self.rh_asset.upper()}'
2026-04-30 04:32:49 +00:00
# @dataclass(kw_only=True)
# class Aster(Perpetual_Exchange):
# name: str = 'Aster'
# lh_asset: str = 'ETH'
# rh_asset: str = 'USDT'
2026-04-25 23:43:28 +00:00
2026-04-30 04:32:49 +00:00
# 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))
2026-04-25 23:43:28 +00:00
2026-04-30 04:32:49 +00:00
# @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))