This commit is contained in:
2026-05-04 18:04:45 +00:00
parent b05f389e49
commit 4eadc32f03
12 changed files with 10709 additions and 2496 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,12 @@
{ {
"Updated_Timestamp": 1777667398908, "Updated_Timestamp": 1777828655743,
"Config": { "Config": {
"Loop_Sleep_Sec": 0.0, "Loop_Sleep_Sec": 0.0,
"Max_Order_Over_Notional_Ratio": 1.05, "Max_Order_Over_Notional_Ratio": 1.05,
"Max_Target_Notional": 0.0, "Max_Target_Notional": 0.0,
"Min_Time_To_Funding_Minutes": 60, "Min_Time_To_Funding_Minutes": 57,
"Min_Fund_Rate_Pct_To_Trade": 0.0, "Min_Fund_Rate_Pct_To_Trade": 0.0005,
"Price_Worsener_Aster": 0, "Price_Worsener_Aster": 1,
"Price_Worsener_Extend": -1, "Price_Worsener_Extend": -1,
"Switch_To_Taker_Seconds": 3, "Switch_To_Taker_Seconds": 3,
"Target_Open_Cash_Position": 10 "Target_Open_Cash_Position": 10

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,6 @@ df_leverage_by_exch = pd.DataFrame(data=leverage.LEVERAGE_BY_EXCH)
### Database ### ### Database ###
# CON: AsyncContextManager | None = None # CON: AsyncContextManager | None = None
VAL_KEY: valkey.Valkey VAL_KEY: valkey.Valkey
VK_OUT: str = 'fr_engine_best_fund_rate_output'
### Logging ### ### Logging ###
load_dotenv() load_dotenv()
@@ -36,6 +35,11 @@ REFRESH_MKT_VOLUME_EVERY_SEC: int = 30
Mkt_Info_Last_Refresh_TS_ms: int = 0 Mkt_Info_Last_Refresh_TS_ms: int = 0
Mkt_Volume_Last_Refresh_TS_ms: int = 0 Mkt_Volume_Last_Refresh_TS_ms: int = 0
### TODO: score by volume, how long since last trade?, volatility, volume by time of day (active or dormant period?), funding rate consistency (% one side last 24hrs and from active close to active open periods). trade cost estimate?, max tradeable notional.
### TODO: figure out what is max percent of volume i can trade - TCA kinda? what is ideal slice size?
### TODO: Redesign so Algo allocates across the best markets with a waterfall method until at target collateral usage. order waterfall by score above^^
### TODO: NG display grid of markets sorted by above score. top left is control panel, top right is graph (goes to mkt you click on from table) (maybe tabs for different graph views/groups, e.g. PnL total or all mkts percent to liquidate, pov by market etc.) middle bottom is markets table (tabs for open orders, open positions, pnl)
### Funcs - Load Data ### ### Funcs - Load Data ###
async def get_extended_markets_info() -> pd.DataFrame: async def get_extended_markets_info() -> pd.DataFrame:
r: dict = json.loads(s=requests.get(url='https://api.starknet.extended.exchange/api/v1/info/markets').text) r: dict = json.loads(s=requests.get(url='https://api.starknet.extended.exchange/api/v1/info/markets').text)
@@ -46,8 +50,12 @@ async def get_extended_markets_info() -> pd.DataFrame:
df['daily_volume'] = df['marketStats'].apply(lambda x: x.get('dailyVolume',{})).astype(float) df['daily_volume'] = df['marketStats'].apply(lambda x: x.get('dailyVolume',{})).astype(float)
df['min_order_size'] = df['tradingConfig'].apply(lambda x: x.get('minOrderSize',{})) df['min_order_size'] = df['tradingConfig'].apply(lambda x: x.get('minOrderSize',{}))
df['min_price'] = df['tradingConfig'].apply(lambda x: x.get('minPriceChange',{})) df['min_price'] = df['tradingConfig'].apply(lambda x: x.get('minPriceChange',{}))
df['min_notional'] = 0
df['min_lot_size'] = df['tradingConfig'].apply(lambda x: x.get('minOrderSizeChange',{}))
df['max_leverage'] = df['tradingConfig'].apply(lambda x: x.get('maxLeverage',{})) df['max_leverage'] = df['tradingConfig'].apply(lambda x: x.get('maxLeverage',{}))
#### TODO: ADD IN LOT SIZE FOR ROUND LOTS (SEE IPYNB)
print('Extend markets info refreshed successfully') print('Extend markets info refreshed successfully')
return df return df
@@ -63,7 +71,9 @@ async def get_aster_exch_info() -> pd.DataFrame:
df = pd.DataFrame(r['symbols']) df = pd.DataFrame(r['symbols'])
df['min_order_size'] = df['filters'].apply(lambda x: [f for f in x if f.get('filterType', None) == 'LOT_SIZE'][0]['minQty'] ) df['min_order_size'] = df['filters'].apply(lambda x: [f for f in x if f.get('filterType', None) == 'LOT_SIZE'][0]['minQty'] )
df['min_price'] = df['filters'].apply(lambda x: [f for f in x if f.get('filterType', None) == 'PRICE_FILTER'][0]['minPrice'] ) df['min_price'] = df['filters'].apply(lambda x: [f for f in x if f.get('filterType', None) == 'PRICE_FILTER'][0]['minPrice'] )
df['min_notional'] = df['filters'].apply(lambda x: [f for f in x if f.get('filterType', None) == 'MIN_NOTIONAL'][0]['notional'] )
df['min_lot_size'] = df['filters'].apply(lambda x: [f for f in x if f.get('filterType', None) == 'LOT_SIZE'][0]['stepSize'] )
fut_acct_ticker_stats: dict = { fut_acct_ticker_stats: dict = {
"url": "/fapi/v3/ticker/24hr", "url": "/fapi/v3/ticker/24hr",
"method": "GET", "method": "GET",
@@ -71,8 +81,9 @@ async def get_aster_exch_info() -> pd.DataFrame:
} }
r: dict = await aster_auth.post_authenticated_url(fut_acct_ticker_stats) # ty:ignore[invalid-assignment] r: dict = await aster_auth.post_authenticated_url(fut_acct_ticker_stats) # ty:ignore[invalid-assignment]
df_stats = pd.DataFrame(r) df_stats = pd.DataFrame(r)
df_stats['last_trade_ts_ast'] = df_stats['closeTime']
df = df.merge(df_stats[['symbol','quoteVolume']].rename({'quoteVolume':'daily_volume'}, axis=1), on='symbol', how='left') df = df.merge(df_stats[['symbol','quoteVolume','last_trade_ts_ast']].rename({'quoteVolume':'daily_volume'}, axis=1), on='symbol', how='left')
df['daily_volume'] = df['daily_volume'].astype(float) df['daily_volume'] = df['daily_volume'].astype(float)
@@ -87,8 +98,8 @@ def load_aster_current_fr(df_aster_exch_info: pd.DataFrame) -> pd.DataFrame:
df['funding_rate_updated_dt'] = pd.to_datetime(df['funding_rate_updated_ts_ms'], unit='ms') df['funding_rate_updated_dt'] = pd.to_datetime(df['funding_rate_updated_ts_ms'], unit='ms')
df['funding_rate'] = df['funding_rate'].astype(float) df['funding_rate'] = df['funding_rate'].astype(float)
df['time_delta_to_next_funding'] = pd.to_datetime(df['next_funding_ts'], unit='ms') - pd.Timestamp.now() df['time_delta_to_next_funding'] = pd.to_datetime(df['next_funding_ts'], unit='ms') - pd.Timestamp.now()
df = df.merge(df_aster_exch_info[['symbol','daily_volume','min_order_size','min_price']], on='symbol', how='left') df = df.merge(df_aster_exch_info[['symbol','daily_volume','min_order_size','min_price','min_lot_size','min_notional', 'last_trade_ts_ast']], on='symbol', how='left')
return df return df
def load_extend_current_fr(df_mkt_stats: pd.DataFrame) -> pd.DataFrame: def load_extend_current_fr(df_mkt_stats: pd.DataFrame) -> pd.DataFrame:
@@ -97,8 +108,8 @@ def load_extend_current_fr(df_mkt_stats: pd.DataFrame) -> pd.DataFrame:
df: pd.DataFrame = df[['symbol','funding_rate_updated_ts_ms','funding_rate']] df: pd.DataFrame = df[['symbol','funding_rate_updated_ts_ms','funding_rate']]
df['funding_rate_updated_dt'] = pd.to_datetime(df['funding_rate_updated_ts_ms'], unit='ms') df['funding_rate_updated_dt'] = pd.to_datetime(df['funding_rate_updated_ts_ms'], unit='ms')
df['funding_rate'] = df['funding_rate'].astype(float) df['funding_rate'] = df['funding_rate'].astype(float)
df: pd.DataFrame = df.merge(df_mkt_stats[['name','assetName','status','funding_rate_ts','daily_volume','min_order_size','min_price']].rename({'name':'symbol','funding_rate_ts':'next_funding_ts'}, axis=1), on='symbol', how='left') df = df.merge(df_mkt_stats[['name','assetName','status','funding_rate_ts','min_order_size','min_price','min_lot_size','min_notional','daily_volume']].rename({'name':'symbol','funding_rate_ts':'next_funding_ts'}, axis=1), on='symbol', how='left')
df: pd.DataFrame = df.loc[df['status']=='ACTIVE',:] df: pd.DataFrame = df.loc[df['status']=='ACTIVE',:]
df['USDT_Symbol'] = df['assetName'] + 'USDT' df['USDT_Symbol'] = df['assetName'] + 'USDT'
@@ -130,35 +141,69 @@ async def loop() -> None:
df_comb_fr['net_mult'] = df_comb_fr['net_mult'].round(2) df_comb_fr['net_mult'] = df_comb_fr['net_mult'].round(2)
df_comb_fr['net_mult_x_net_fr_abs'] = df_comb_fr['net_funding_rate_abs'] * df_comb_fr['net_mult'] df_comb_fr['net_mult_x_net_fr_abs'] = df_comb_fr['net_funding_rate_abs'] * df_comb_fr['net_mult']
df_best_fr_rate = df_comb_fr[['symbol_ext','symbol_ast','daily_volume_ext','daily_volume_ast','min_price_ext','min_price_ast','min_order_size_ext','min_order_size_ast','min_lot_size_ext','min_lot_size_ast','min_notional_ext','min_notional_ast','funding_rate_ext','funding_rate_ast','max_leverage_ext','max_leverage_ast','lh_asset_ext','lh_asset_ast','rh_asset_ext','rh_asset_ast','net_mult_x_net_fr_abs','net_funding_rate_abs','net_funding_rate','next_funding_at_same_time','last_trade_ts_ast']].sort_values(by='net_mult_x_net_fr_abs', ascending=False).reset_index(drop=True)
df_best_fr_rate: pd.DataFrame = df_comb_fr[['symbol_ext','symbol_ast','daily_volume_ext','daily_volume_ast','funding_rate_ext','funding_rate_ast','min_price_ext','min_price_ast','min_order_size_ext','min_order_size_ast','max_leverage_ext','max_leverage_ast','lh_asset_ext','lh_asset_ast','rh_asset_ext','rh_asset_ast','net_mult_x_net_fr_abs','net_funding_rate_abs','net_funding_rate','next_funding_at_same_time']].sort_values(by='net_mult_x_net_fr_abs', ascending=False).reset_index(drop=True)
min_daily_volume = 100_000
df_best_fr_rate = df_best_fr_rate.loc[ (df_best_fr_rate['daily_volume_ast']>=min_daily_volume) & (df_best_fr_rate['daily_volume_ext']>min_daily_volume) ,:].reset_index(drop=True)
ASTER = structs.Perpetual_Exchange(
mult = int(df_best_fr_rate['max_leverage_ast'][0]),
lh_asset = df_best_fr_rate['lh_asset_ast'][0],
rh_asset = df_best_fr_rate['rh_asset_ast'][0],
symbol_asset_separator = '',
initial_funding_rate=float(df_best_fr_rate['funding_rate_ast'][0]),
min_price=float(df_best_fr_rate['min_price_ast'][0]),
min_order_size=float(df_best_fr_rate['min_order_size_ast'][0]),
)
EXTEND = structs.Perpetual_Exchange(
mult = int(df_best_fr_rate['max_leverage_ext'][0]),
lh_asset = df_best_fr_rate['lh_asset_ext'][0],
rh_asset = df_best_fr_rate['rh_asset_ext'][0],
symbol_asset_separator = '-',
initial_funding_rate=float(df_best_fr_rate['funding_rate_ext'][0]),
min_price=float(df_best_fr_rate['min_price_ext'][0]),
min_order_size=float(df_best_fr_rate['min_order_size_ext'][0]),
)
best_next_funding_pair: dict[str, dict] = {'ASTER': asdict(obj=ASTER), 'EXTEND': asdict(obj=EXTEND)}
VAL_KEY.set(name=VK_OUT, value=json.dumps(obj=best_next_funding_pair)) # min_daily_volume = 100_000
# df_best_fr_rate = df_best_fr_rate.loc[ (df_best_fr_rate['daily_volume_ast']>=min_daily_volume) & (df_best_fr_rate['daily_volume_ext']>min_daily_volume) ,:].reset_index(drop=True)
last_trade_max_ts = []
for index, row in df_best_fr_rate.iterrows():
r = json.loads(requests.get(f'https://api.starknet.extended.exchange/api/v1/info/markets/{row['symbol_ext']}/trades').text)
max_ts = max([t['T'] for t in r['data']])
last_trade_max_ts.append({'symbol_ext':row['symbol_ext'],'last_trade_ts_ext': max_ts})
time.sleep(0.01)
df_best_fr_rate = df_best_fr_rate.merge(pd.DataFrame(last_trade_max_ts), on='symbol_ext', how='left')
df_best_fr_rate['last_trade_ts_dt_ast'] = pd.to_datetime(df_best_fr_rate['last_trade_ts_ast'], unit='ms')
df_best_fr_rate['last_trade_ts_dt_ext'] = pd.to_datetime(df_best_fr_rate['last_trade_ts_ext'], unit='ms')
df_best_fr_rate = df_best_fr_rate.loc[( (datetime.now().timestamp()*1000 )-df_best_fr_rate['last_trade_ts_ast']) < (3*60*1000) ]
df_best_fr_rate = df_best_fr_rate.loc[( (datetime.now().timestamp()*1000 )-df_best_fr_rate['last_trade_ts_ext']) < (15*60*1000) ]
# print(df_best_fr_rate.columns)
# print(df_best_fr_rate.iloc[0])
if len(df_best_fr_rate) < 1:
raise ValueError(f'NO BFR RATE: {df_best_fr_rate}')
try:
ASTER = structs.Perpetual_Exchange(
mult = int(df_best_fr_rate['max_leverage_ast'].iloc[0]),
lh_asset = df_best_fr_rate['lh_asset_ast'].iloc[0],
rh_asset = df_best_fr_rate['rh_asset_ast'].iloc[0],
symbol_asset_separator = '',
initial_funding_rate=float(df_best_fr_rate['funding_rate_ast'].iloc[0]),
min_price=float(df_best_fr_rate['min_price_ast'].iloc[0]),
min_order_size=float(df_best_fr_rate['min_order_size_ast'].iloc[0]),
min_lot_size=float(df_best_fr_rate['min_lot_size_ast'].iloc[0]),
min_notional=float(df_best_fr_rate['min_notional_ast'].iloc[0]),
)
EXTEND = structs.Perpetual_Exchange(
mult = int(df_best_fr_rate['max_leverage_ext'].iloc[0]),
lh_asset = df_best_fr_rate['lh_asset_ext'].iloc[0],
rh_asset = df_best_fr_rate['rh_asset_ext'].iloc[0],
symbol_asset_separator = '-',
initial_funding_rate=float(df_best_fr_rate['funding_rate_ext'].iloc[0]),
min_price=float(df_best_fr_rate['min_price_ext'].iloc[0]),
min_order_size=float(df_best_fr_rate['min_order_size_ext'].iloc[0]),
min_lot_size=float(df_best_fr_rate['min_lot_size_ext'].iloc[0]),
min_notional=float(df_best_fr_rate['min_notional_ext'].iloc[0]),
)
except Exception as e:
logging.critical(f'Failed to build ASTER/EXTEND objs err: {e}; df cols: {df_best_fr_rate.columns}')
logging.error(traceback.format_exc())
continue
best_next_funding_pair: dict[str, dict] = {'ASTER': asdict(obj=ASTER), 'EXTEND': asdict(obj=EXTEND)}
VAL_KEY.set(name='fr_engine_best_fund_rate_output', value=json.dumps(obj=best_next_funding_pair))
master_data = df_comb_fr[
['symbol_ast','max_leverage_ast','lh_asset_ast','rh_asset_ast','funding_rate_ast','min_price_ast','min_order_size_ast','min_lot_size_ast','min_notional_ast',
'symbol_ext','max_leverage_ext','lh_asset_ext','rh_asset_ext','funding_rate_ext','min_price_ext','min_order_size_ext','min_lot_size_ext','min_notional_ext']
].to_json(orient='records')
VAL_KEY.set(name='fr_engine_best_fund_rate_master', value=str(master_data))
print(df_best_fr_rate[['symbol_ext','max_leverage_ext','funding_rate_ast','funding_rate_ext','net_funding_rate','daily_volume_ast']].head(10)) print(df_best_fr_rate[['symbol_ext','max_leverage_ext','funding_rate_ast','funding_rate_ext','net_funding_rate','daily_volume_ast']].head(10))
logging.info(f'BFR REFRESHED @ {datetime.now()}')
time.sleep(LOOP_SLEEP_SEC) time.sleep(LOOP_SLEEP_SEC)
continue continue
except valkey.exceptions.ConnectionError as e: except valkey.exceptions.ConnectionError as e:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

246
main.py
View File

@@ -1,4 +1,4 @@
from orjson import JSONDecodeError
from x10.utils.http import WrappedApiResponse from x10.utils.http import WrappedApiResponse
from x10.perpetual.trading_client.trading_client import PerpetualTradingClient from x10.perpetual.trading_client.trading_client import PerpetualTradingClient
import asyncio import asyncio
@@ -9,7 +9,7 @@ import os
import time import time
import traceback import traceback
from datetime import datetime, timezone from datetime import datetime, timezone
from decimal import ROUND_DOWN, ROUND_HALF_UP, Decimal from decimal import ROUND_DOWN, ROUND_UP, ROUND_HALF_UP, Decimal
from typing import AsyncContextManager from typing import AsyncContextManager
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict
from typing import Any from typing import Any
@@ -114,10 +114,15 @@ async def get_aster_account_open_symbols() -> list[str]:
"url": "/fapi/v3/positionRisk", "url": "/fapi/v3/positionRisk",
"method": "GET", "method": "GET",
"params": { "params": {
'symbol': ASTER.symbol, 'symbol':''
} }
} }
resp: list = await aster_auth.post_authenticated_url(req=fut_acct_positionRisk) # ty:ignore[invalid-assignment] try:
resp: list = await aster_auth.post_authenticated_url(req=fut_acct_positionRisk) # ty:ignore[invalid-assignment]
except Exception as e:
logging.critical(f'JSONDecodeError trying to get Aster open orders: {e}; resp: {resp}')
await kill_algo()
resp: list = []
ld = [ utils.symbol_to_extend_fmt(x['symbol']) for x in resp if abs(float(x.get('positionAmt', 0))) > 0] ld = [ utils.symbol_to_extend_fmt(x['symbol']) for x in resp if abs(float(x.get('positionAmt', 0))) > 0]
return ld return ld
@@ -144,10 +149,11 @@ async def get_aster_notional_position(resp: list | None = None):
} }
try: try:
resp: list = await aster_auth.post_authenticated_url(req=fut_acct_positionRisk) # ty:ignore[invalid-assignment] resp: list = await aster_auth.post_authenticated_url(req=fut_acct_positionRisk) # ty:ignore[invalid-assignment]
except JSONDecodeError as e: except Exception as e:
logging.warning(f'JSONDecodeError trying to get Aster notional: {e}; resp: {resp}') logging.critical(f'JSONDecodeError trying to get Aster notional: {e}; resp: {resp}')
time.sleep(0.1) await kill_algo()
resp: list = await aster_auth.post_authenticated_url(req=fut_acct_positionRisk) # ty:ignore[invalid-assignment] resp: list = []
d = [x for x in resp if x.get('symbol', None) == ASTER.symbol][0] d = [x for x in resp if x.get('symbol', None) == ASTER.symbol][0]
d['timestamp_arrival'] = round(datetime.now().timestamp()*1000) d['timestamp_arrival'] = round(datetime.now().timestamp()*1000)
@@ -168,10 +174,10 @@ async def get_aster_notional_position(resp: list | None = None):
ASTER_NOTIONAL_POSITION = float(d['notional']) - ASTER_UNREALIZED_PNL ASTER_NOTIONAL_POSITION = float(d['notional']) - ASTER_UNREALIZED_PNL
else: else:
ASTER_NOTIONAL_POSITION = float(d['position_amount'])*float(d['entry_price']) ASTER_NOTIONAL_POSITION = float(d['position_amount'])*float(d['entry_price'])
# if not resp: # this can never evaluate if d.get('leverage') is not None:
# ASTER.mult = float(d['leverage']) ASTER.mult = int(d['leverage'])
if abs(ASTER_NOTIONAL_POSITION) > ALGO_CONFIG.Config.Max_Target_Notional*ALGO_CONFIG.Config.Max_Order_Over_Notional_Ratio: if abs(ASTER_NOTIONAL_POSITION) > ALGO_CONFIG.Config.Max_Target_Notional*ALGO_CONFIG.Config.Max_Order_Over_Notional_Ratio:
logging.info(f'BAD NOTIONAL - ASTER CHANGE: {previous_notional_position} -> {ASTER_NOTIONAL_POSITION}; UR PNL: {ASTER_UNREALIZED_PNL}; MULT: {ASTER.mult}; d: {d}; resp: {resp}') logging.info(f'BAD NOTIONAL - ASTER CHANGE: {previous_notional_position} -> {ASTER_NOTIONAL_POSITION}; UR PNL: {ASTER_UNREALIZED_PNL}; MULT: {ASTER.mult}; d: {d}; resp: {resp}; max_tgt_notional: {ALGO_CONFIG.Config.Max_Target_Notional}')
await kill_algo() await kill_algo()
if ASTER_NOTIONAL_POSITION != previous_notional_position: if ASTER_NOTIONAL_POSITION != previous_notional_position:
logging.info(f'ASTER NOTIONAL CHANGE: {previous_notional_position:.2f} -> {ASTER_NOTIONAL_POSITION:.2f}; UR PNL: {ASTER_UNREALIZED_PNL:.2f}; MULT: {ASTER.mult:.0f}; resp: {bool(resp)}') logging.info(f'ASTER NOTIONAL CHANGE: {previous_notional_position:.2f} -> {ASTER_NOTIONAL_POSITION:.2f}; UR PNL: {ASTER_UNREALIZED_PNL:.2f}; MULT: {ASTER.mult:.0f}; resp: {bool(resp)}')
@@ -210,13 +216,15 @@ async def get_extend_notional(resp: list | None = None):
pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND.symbol] pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND.symbol]
if pos_dict: if pos_dict:
pos_dict = pos_dict[0] pos_dict = pos_dict[0]
pos_dict['timestamp_arrival'] = round(datetime.now().timestamp()*1000)
else: else:
pos_dict = {} pos_dict = {}
pos_dict['side'] = 'LONG' pos_dict['side'] = 'LONG'
pos_dict['value'] = 0.00 pos_dict['value'] = 0.00
pos_dict['unrealised_pnl'] = 0.00
pos_dict['timestamp_arrival'] = round(datetime.now().timestamp()*1000)
logging.info('get_extend_notional - No Positions') logging.info('get_extend_notional - No Positions')
pos_dict['timestamp_arrival'] = round(datetime.now().timestamp()*1000)
else: else:
pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND.symbol] pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND.symbol]
if pos_dict: if pos_dict:
@@ -225,14 +233,18 @@ async def get_extend_notional(resp: list | None = None):
pos_dict = {} pos_dict = {}
pos_dict['side'] = 'LONG' pos_dict['side'] = 'LONG'
pos_dict['value'] = 0.00 pos_dict['value'] = 0.00
pos_dict['unrealised_pnl'] = 0.00
pos_dict['timestamp_arrival'] = round(datetime.now().timestamp()*1000)
# logging.info('get_extend_notional - No Positions') # logging.info('get_extend_notional - No Positions')
pos_dict['timestamp_arrival'] = round(datetime.now().timestamp()*1000) # pos_dict['timestamp_arrival'] = round(datetime.now().timestamp()*1000)
if previous_notional_obj is not None: if previous_notional_obj is not None:
if previous_notional_obj['timestamp_arrival'] > pos_dict['timestamp_arrival']: if previous_notional_obj['timestamp_arrival'] > pos_dict['timestamp_arrival']:
# logging.info(f'EXTEND NOTIONAL: prev timestamp ({pd.to_datetime(previous_notional_obj['timestamp_arrival'], unit='ms')}) > new timestamp ({pd.to_datetime(d['timestamp_arrival'], unit='ms')}); skipping') # logging.info(f'EXTEND NOTIONAL: prev timestamp ({pd.to_datetime(previous_notional_obj['timestamp_arrival'], unit='ms')}) > new timestamp ({pd.to_datetime(pos_dict['timestamp_arrival'], unit='ms')}); skipping')
return return
else:
previous_notional_obj = {}
EXTEND_NOTIONAL_OBJ = pos_dict EXTEND_NOTIONAL_OBJ = pos_dict
@@ -252,7 +264,7 @@ async def get_extend_notional(resp: list | None = None):
logging.info(f'BAD NOTIONAL - EXTEND CHANGE: {previous_notional_position} -> {EXTEND_NOTIONAL_POSITION}; UR PNL: {EXTEND_UNREALIZED_PNL}; MULT: {EXTEND.mult}; d: {pos_dict}; resp: {resp}') logging.info(f'BAD NOTIONAL - EXTEND CHANGE: {previous_notional_position} -> {EXTEND_NOTIONAL_POSITION}; UR PNL: {EXTEND_UNREALIZED_PNL}; MULT: {EXTEND.mult}; d: {pos_dict}; resp: {resp}')
await kill_algo() await kill_algo()
if EXTEND_NOTIONAL_POSITION != previous_notional_position: if EXTEND_NOTIONAL_POSITION != previous_notional_position:
logging.info(f'EXTEND NOTIONAL CHANGE: {previous_notional_position} -> {EXTEND_NOTIONAL_POSITION:.2f}; UR PNL: {EXTEND_UNREALIZED_PNL:.2f}; MULT: {EXTEND.mult}; resp: {bool(resp)}') logging.info(f'EXTEND NOTIONAL CHANGE: {previous_notional_position} [{previous_notional_obj.get('timestamp_arrival')}] -> {EXTEND_NOTIONAL_POSITION:.2f} [{EXTEND_NOTIONAL_OBJ['timestamp_arrival']}]; UR PNL: {EXTEND_UNREALIZED_PNL:.2f}; MULT: {EXTEND.mult}; resp: {bool(resp)}')
### EXCHANGE INFO ### ### EXCHANGE INFO ###
async def get_aster_exch_info(symbol_override: str | None = None): async def get_aster_exch_info(symbol_override: str | None = None):
@@ -271,6 +283,7 @@ async def get_aster_exch_info(symbol_override: str | None = None):
d: dict = [d for d in s if d.get('symbol', None) == ASTER.symbol][0] d: dict = [d for d in s if d.get('symbol', None) == ASTER.symbol][0]
f: dict = [f for f in d['filters'] if f.get('filterType', None) == 'LOT_SIZE'][0] f: dict = [f for f in d['filters'] if f.get('filterType', None) == 'LOT_SIZE'][0]
q: dict = [f for f in d['filters'] if f.get('filterType', None) == 'PRICE_FILTER'][0] q: dict = [f for f in d['filters'] if f.get('filterType', None) == 'PRICE_FILTER'][0]
n: dict = [f for f in d['filters'] if f.get('filterType', None) == 'MIN_NOTIONAL'][0]
min_qty = float(f['minQty']) min_qty = float(f['minQty'])
min_qty = int(min_qty) if min_qty == int(min_qty) else min_qty min_qty = int(min_qty) if min_qty == int(min_qty) else min_qty
@@ -279,6 +292,7 @@ async def get_aster_exch_info(symbol_override: str | None = None):
min_price = int(min_price) if min_price == int(min_price) else min_price min_price = int(min_price) if min_price == int(min_price) else min_price
ASTER.min_order_size = min_qty ASTER.min_order_size = min_qty
ASTER.min_price = min_price ASTER.min_price = min_price
ASTER.min_notional = float(n['notional'])
async def get_extend_exch_info(symbol_override: str | None = None): async def get_extend_exch_info(symbol_override: str | None = None):
global EXTEND global EXTEND
@@ -290,6 +304,7 @@ async def get_extend_exch_info(symbol_override: str | None = None):
EXTEND.min_order_size = float(r[EXTEND.symbol].trading_config.min_order_size) EXTEND.min_order_size = float(r[EXTEND.symbol].trading_config.min_order_size)
EXTEND.min_price = float(r[EXTEND.symbol].trading_config.min_price_change) EXTEND.min_price = float(r[EXTEND.symbol].trading_config.min_price_change)
### CANCEL ORDERS ### ### CANCEL ORDERS ###
async def aster_cancel_all_orders(): async def aster_cancel_all_orders():
cancel_all_open_orders = { cancel_all_open_orders = {
@@ -367,13 +382,11 @@ async def run_algo():
ASTER_FUND_RATE = ASTER_FUND_RATE * -1 ASTER_FUND_RATE = ASTER_FUND_RATE * -1
EXTEND_FUND_RATE = EXTEND_FUND_RATE * -1 EXTEND_FUND_RATE = EXTEND_FUND_RATE * -1
if ALGO_CONFIG.Overrides.Flatten_Open_Positions or ALGO_CONFIG.Overrides.Flatten_Open_Positions_Opportunistic:
ROUNDING = ROUND_HALF_UP
else:
ROUNDING = ROUND_DOWN
ASTER_FUND_RATE_TIME = float(ASTER_FUND_RATE_DICT.get('next_funding_time_ts_ms', 0)) ASTER_FUND_RATE_TIME = float(ASTER_FUND_RATE_DICT.get('next_funding_time_ts_ms', 0))
ASTER_FUND_RATE_TIME = ASTER_FUND_RATE_TIME+(60*60*1000) if ASTER_FUND_RATE_TIME < (datetime.now().timestamp()*1000) else ASTER_FUND_RATE_TIME
EXTEND_FUND_RATE_TIME = max([float(EXTENDED_FUND_RATE_DICT.get('next_funding_time_ts_ms', 0)), 0]) EXTEND_FUND_RATE_TIME = max([float(EXTENDED_FUND_RATE_DICT.get('next_funding_time_ts_ms', 0)), 0])
EXTEND_FUND_RATE_TIME = EXTEND_FUND_RATE_TIME+(60*60*1000) if EXTEND_FUND_RATE_TIME < (datetime.now().timestamp()*1000) else EXTEND_FUND_RATE_TIME
ASTER_TICKER_DICT: Any = VAL_KEY.get('fut_ticker_aster') ASTER_TICKER_DICT: Any = VAL_KEY.get('fut_ticker_aster')
ASTER_TICKER_DICT: dict = json.loads(s=ASTER_TICKER_DICT) if ASTER_TICKER_DICT is not None else {} ASTER_TICKER_DICT: dict = json.loads(s=ASTER_TICKER_DICT) if ASTER_TICKER_DICT is not None else {}
@@ -510,16 +523,39 @@ async def run_algo():
if abs( ASTER_NOTIONAL_POSITION ) > 0.00 or abs( EXTEND_NOTIONAL_POSITION ) > 0.00: if abs( ASTER_NOTIONAL_POSITION ) > 0.00 or abs( EXTEND_NOTIONAL_POSITION ) > 0.00:
if ALGO_CONFIG.Logging.Print_Summary_Each_Loop: if ALGO_CONFIG.Logging.Print_Summary_Each_Loop:
print(f'Symbol switch [{ASTER.symbol} > {best_symbol_by_exchange_aster.symbol}] - Flattening Positions') print(f'Symbol switch [{ASTER.symbol} > {best_symbol_by_exchange_aster.symbol}] - Flattening Positions')
ALGO_CONFIG.Overrides.Flatten_Open_Positions = True ALGO_CONFIG.Overrides.Flatten_Open_Positions_Opportunistic = True
else: else:
logging.info('Balances Flattened - Updating to Trade New Symbols:') logging.info('Balances Flattened - Updating to Trade New Symbols:')
logging.info(f' ASTER.symbol -> {best_symbol_by_exchange_aster.symbol}') logging.info(f' ASTER.symbol -> {best_symbol_by_exchange_aster.symbol}')
logging.info(f' EXTEND.symbol -> {best_symbol_by_exchange_extend.symbol}') logging.info(f' EXTEND.symbol -> {best_symbol_by_exchange_extend.symbol}')
ALGO_CONFIG.Overrides.Flatten_Open_Positions = False ALGO_CONFIG.Overrides.Flatten_Open_Positions_Opportunistic = False
if Open_Symbols: if Open_Symbols:
logging.info(f'OPEN SYMBOLS TO CLOSE: {Open_Symbols}') logging.info(f'OPEN SYMBOLS TO CLOSE: {Open_Symbols}')
await get_aster_exch_info(symbol_override=Open_Symbols[0]) master_data = json.loads(s=VAL_KEY.get(name='fr_engine_best_fund_rate_master')) # ty:ignore[invalid-argument-type]
await get_extend_exch_info(symbol_override=Open_Symbols[0]) open_symbol_to_work = Open_Symbols[0]
current_pos_master_ast = [d for d in master_data if d.get('symbol_ext') == open_symbol_to_work][0]
ASTER = structs.Perpetual_Exchange(
mult = int(current_pos_master_ast['max_leverage_ast']),
lh_asset = current_pos_master_ast['lh_asset_ast'],
rh_asset = current_pos_master_ast['rh_asset_ast'],
symbol_asset_separator = '',
initial_funding_rate=float(current_pos_master_ast['funding_rate_ast']),
min_price=float(current_pos_master_ast['min_price_ast']),
min_order_size=float(current_pos_master_ast['min_order_size_ast']),
min_lot_size=float(current_pos_master_ast['min_lot_size_ast']),
min_notional=float(current_pos_master_ast['min_notional_ast']),
)
EXTEND = structs.Perpetual_Exchange(
mult = int(current_pos_master_ast['max_leverage_ext']),
lh_asset = current_pos_master_ast['lh_asset_ext'],
rh_asset = current_pos_master_ast['rh_asset_ext'],
symbol_asset_separator = '-',
initial_funding_rate=float(current_pos_master_ast['funding_rate_ext']),
min_price=float(current_pos_master_ast['min_price_ext']),
min_order_size=float(current_pos_master_ast['min_order_size_ext']),
min_lot_size=float(current_pos_master_ast['min_lot_size_ext']),
min_notional=float(current_pos_master_ast['min_notional_ext']),
)
Open_Symbols.pop(0) Open_Symbols.pop(0)
await get_aster_notional_position() await get_aster_notional_position()
await get_extend_notional() await get_extend_notional()
@@ -565,7 +601,13 @@ async def run_algo():
# else: # else:
# logging.info('NET FUNDING = 0.00; NO OPEN ORDERS; Waiting...') # logging.info('NET FUNDING = 0.00; NO OPEN ORDERS; Waiting...')
# time.sleep(5) # time.sleep(5)
if ALGO_CONFIG.Overrides.Flatten_Open_Positions or ALGO_CONFIG.Overrides.Flatten_Open_Positions_Opportunistic or ALPHA_TGT_NOTIONAL==0.00:
# ROUNDING = ROUND_UP
ROUNDING = ROUND_HALF_UP
else:
ROUNDING = ROUND_DOWN
if ALPHA_EXCH == 'EXTEND': if ALPHA_EXCH == 'EXTEND':
ASTER_TGT_NOTIONAL = ALPHA_TGT_NOTIONAL*-1 ASTER_TGT_NOTIONAL = ALPHA_TGT_NOTIONAL*-1
@@ -603,28 +645,46 @@ async def run_algo():
Expected_Alpha = ( ( ASTER_TOB_PX - EXTEND_TOB_PX ) / (( ASTER_TOB_PX + EXTEND_TOB_PX ) / 2) ) Expected_Alpha = ( ( ASTER_TOB_PX - EXTEND_TOB_PX ) / (( ASTER_TOB_PX + EXTEND_TOB_PX ) / 2) )
Expected_Alpha_Net_FR = abs(NEXT_NET_FUNDING_RATE) + Expected_Alpha Expected_Alpha_Net_FR = abs(NEXT_NET_FUNDING_RATE) + Expected_Alpha
Expected_Alpha_Net_FR_w_Taker = Expected_Alpha_Net_FR-0.0002 Expected_Alpha_Net_FR_w_Taker = Expected_Alpha_Net_FR-0.00025
Expected_Alpha_w_Taker = Expected_Alpha-0.0002 Expected_Alpha_w_Taker = Expected_Alpha-0.00025
EXTEND_TGT_NOTIONAL = ASTER_NOTIONAL_POSITION * -1 EXTEND_TGT_NOTIONAL = ASTER_NOTIONAL_POSITION * -1
ASTER_TGT_TAIL = ASTER_TGT_NOTIONAL - ( float(ASTER_NOTIONAL_POSITION) + float(ASTER_UNREALIZED_PNL) ) ASTER_TGT_TAIL = ASTER_TGT_NOTIONAL - ( float(ASTER_NOTIONAL_POSITION) + float(ASTER_UNREALIZED_PNL) )
EXTEND_TGT_TAIL = EXTEND_TGT_NOTIONAL - ( float(EXTEND_NOTIONAL_POSITION) + float(EXTEND_UNREALIZED_PNL) ) # EXTEND_TGT_TAIL = EXTEND_TGT_NOTIONAL - ( float(EXTEND_NOTIONAL_POSITION) + float(EXTEND_UNREALIZED_PNL) )
EXTEND_TGT_TAIL = EXTEND_TGT_NOTIONAL - ( float(EXTEND_NOTIONAL_POSITION) )
# EXTEND_TGT_TAIL = float(ASTER_NOTIONAL_POSITION)*-1 # EXTEND_TGT_TAIL = float(ASTER_NOTIONAL_POSITION)*-1
min_order_size = ASTER.min_order_size min_order_size = ASTER.min_order_size
min_order_size = int(min_order_size) if min_order_size == int(min_order_size) else min_order_size min_order_size = int(min_order_size) if min_order_size == int(min_order_size) else min_order_size
ASTER_TGT_TAIL_BASE_QTY = Decimal(str(float(ASTER_TGT_TAIL) / float(ASTER_TOB_PX))).quantize(Decimal(str(min_order_size)), rounding=ROUNDING) ASTER_TGT_TAIL_BASE_QTY = Decimal(str(float(ASTER_TGT_TAIL) / float(ASTER_TOB_PX))).quantize(Decimal(str(min_order_size)), rounding=ROUNDING)
if ASTER.min_lot_size:
ASTER_TGT_TAIL_BASE_QTY = float(ASTER_TGT_TAIL_BASE_QTY) - ( float(ASTER_TGT_TAIL_BASE_QTY) % ASTER.min_lot_size )
ASTER_TGT_TAIL_BASE_QTY = Decimal(str(ASTER_TGT_TAIL_BASE_QTY)).quantize(Decimal(str(min_order_size)), rounding=ROUNDING)
min_order_size = EXTEND.min_order_size min_order_size = EXTEND.min_order_size
min_order_size = int(min_order_size) if min_order_size == int(min_order_size) else min_order_size min_order_size = int(min_order_size) if min_order_size == int(min_order_size) else min_order_size
EXTEND_TGT_TAIL_BASE_QTY = Decimal(str(float(EXTEND_TGT_TAIL) / float(EXTEND_TOB_PX))).quantize(Decimal(str(min_order_size)), rounding=ROUNDING) EXTEND_TGT_TAIL_BASE_QTY = Decimal(str(float(EXTEND_TGT_TAIL) / float(EXTEND_TOB_PX))).quantize(Decimal(str(min_order_size)), rounding=ROUNDING)
if EXTEND.min_lot_size:
EXTEND_TGT_TAIL_BASE_QTY = float(EXTEND_TGT_TAIL_BASE_QTY) - ( float(EXTEND_TGT_TAIL_BASE_QTY) % EXTEND.min_lot_size )
EXTEND_TGT_TAIL_BASE_QTY = Decimal(str(EXTEND_TGT_TAIL_BASE_QTY)).quantize(Decimal(str(min_order_size)), rounding=ROUNDING)
# MAX_MIN_ORDER_QTY = max([ASTER.min_order_size, EXTEND.min_order_size]) # MAX_MIN_ORDER_QTY = max([ASTER.min_order_size, EXTEND.min_order_size])
ASTER_TGT_TAIL_ORDERABLE = Decimal(str(abs(ASTER_TGT_TAIL_BASE_QTY))) >= Decimal(str(abs(ASTER.min_order_size))) ASTER_TGT_TAIL_ORDERABLE = ( Decimal(str(abs(ASTER_TGT_TAIL_BASE_QTY)) ) >= Decimal(str(abs(ASTER.min_order_size))) ) and ( Decimal(str(abs(ASTER_TGT_TAIL))) > Decimal(str(abs(ASTER.min_notional))) )
EXTEND_TGT_TAIL_ORDERABLE = Decimal(str(abs(EXTEND_TGT_TAIL_BASE_QTY))) >= Decimal(str(abs(EXTEND.min_order_size))) EXTEND_TGT_TAIL_ORDERABLE = ( Decimal(str(abs(EXTEND_TGT_TAIL_BASE_QTY))) >= Decimal(str(abs(EXTEND.min_order_size))) ) and ( Decimal(str(abs(EXTEND_TGT_TAIL))) > Decimal(str(abs(EXTEND.min_notional))) )
# ASTER_TGT_TAIL_ORDERABLE = abs(ASTER_TGT_TAIL_BASE_QTY) >= MAX_MIN_ORDER_QTY
# EXTEND_TGT_TAIL_ORDERABLE = abs(EXTEND_TGT_TAIL_BASE_QTY) >= MAX_MIN_ORDER_QTY if not ASTER_TGT_TAIL_ORDERABLE:
if abs(ASTER_TGT_TAIL_BASE_QTY) > 0:
if ALGO_CONFIG.Overrides.Flatten_Open_Positions or ALGO_CONFIG.Overrides.Flatten_Open_Positions_Opportunistic or ALPHA_TGT_NOTIONAL == 0.00:
logging.info('* Trying to flatten small Aster balance, was originally not orderable.')
ASTER_TGT_TAIL_ORDERABLE = True
if not EXTEND_TGT_TAIL_ORDERABLE:
if abs(EXTEND_TGT_TAIL_BASE_QTY) > 0:
if ALGO_CONFIG.Overrides.Flatten_Open_Positions or ALGO_CONFIG.Overrides.Flatten_Open_Positions_Opportunistic or ALPHA_TGT_NOTIONAL == 0.00:
logging.info('* Trying to flatten small Extend balance, was originally not orderable.')
EXTEND_TGT_TAIL_ORDERABLE = True
# Hedge_Ratio = abs(( abs( max([abs(float(EXTEND_NOTIONAL_POSITION)), 0.01]) / max([abs(float(ASTER_NOTIONAL_POSITION)), 0.01]) ) - 1 ) * 100) # Hedge_Ratio = abs(( abs( max([abs(float(EXTEND_NOTIONAL_POSITION)), 0.01]) / max([abs(float(ASTER_NOTIONAL_POSITION)), 0.01]) ) - 1 ) * 100)
Hedge_Ratio = abs( ( EXTEND_NOTIONAL_POSITION + ASTER_NOTIONAL_POSITION ) / max([ASTER_NOTIONAL_POSITION, 0.01]) ) * 100 Hedge_Ratio = abs( ( EXTEND_NOTIONAL_POSITION + ASTER_NOTIONAL_POSITION ) / max([ASTER_NOTIONAL_POSITION, 0.01]) ) * 100
@@ -652,7 +712,7 @@ async def run_algo():
ASTER: {ASTER_TGT_TAIL_BASE_QTY:.4f} > {ASTER.min_order_size:.4f} min [ Order: {ASTER_TGT_TAIL_ORDERABLE} ] | EXTEND: {EXTEND_TGT_TAIL_BASE_QTY:.4f} > {EXTEND.min_order_size:.4f} min [ Order: {EXTEND_TGT_TAIL_ORDERABLE} ] ASTER: {ASTER_TGT_TAIL_BASE_QTY:.4f} > {ASTER.min_order_size:.4f} min [ Order: {ASTER_TGT_TAIL_ORDERABLE} ] | EXTEND: {EXTEND_TGT_TAIL_BASE_QTY:.4f} > {EXTEND.min_order_size:.4f} min [ Order: {EXTEND_TGT_TAIL_ORDERABLE} ]
ALPHA: {ALPHA_RATIO:.8f} ALPHA_RATIO: {Alpha_Nominator:_.6f} / {Alpha_Denominator:_.6f} (Px Diff: {abs(Alpha_Nominator-Alpha_Denominator):.2f}); Expected_Alpha = {Expected_Alpha:.6f} + FR[{NEXT_NET_FUNDING_RATE:.6f}] = * {Expected_Alpha_Net_FR:.6f} * ALPHA: {ALPHA_RATIO:.8f} ALPHA_RATIO: {Alpha_Nominator:_.6f} / {Alpha_Denominator:_.6f} (Px Diff: {abs(Alpha_Nominator-Alpha_Denominator):.2f}); Expected_Alpha = {Expected_Alpha:.6f} + FR[{NEXT_NET_FUNDING_RATE:.6f}] = * {Expected_Alpha_Net_FR:.6f} *
FEES : TAKER: {0.0002:.2%}; Expected Alpha w Taker = {Expected_Alpha_Net_FR-0.0002:.6f} [w/o FR: {Expected_Alpha_w_Taker:.6f}] FEES : TAKER: {0.00025:.6%}; Expected Alpha w Taker = {Expected_Alpha_Net_FR_w_Taker:.6f} [w/o FR: {Expected_Alpha_w_Taker:.6f}]
HEDGE: {Hedge_Ratio:.2f}% <= {1:.2f}%: {Currently_Hedged} [{EXTEND_NOTIONAL_POSITION:.2f} / {ASTER_NOTIONAL_POSITION:.2f}] HEDGE: {Hedge_Ratio:.2f}% <= {1:.2f}%: {Currently_Hedged} [{EXTEND_NOTIONAL_POSITION:.2f} / {ASTER_NOTIONAL_POSITION:.2f}]
MKT : Aster: {ASTER.symbol} (best: {best_symbol_by_exchange_aster.symbol}) | Extend: {ASTER.symbol} (best: {best_symbol_by_exchange_extend.symbol}) MKT : Aster: {ASTER.symbol} (best: {best_symbol_by_exchange_aster.symbol}) | Extend: {ASTER.symbol} (best: {best_symbol_by_exchange_extend.symbol})
@@ -674,11 +734,16 @@ async def run_algo():
### ROUTES ### ### ROUTES ###
# Just_Rejected_Or_Expired # Just_Rejected_Or_Expired
# MIN_EXPECTED_ALPHA_TO_TRADE = 0.0001 MIN_EXPECTED_ALPHA_TO_TRADE = 0.0000
MIN_EXPECTED_ALPHA_TO_TRADE = abs(NEXT_NET_FUNDING_RATE)*-1 if ALGO_CONFIG.Overrides.Flatten_Open_Positions_Opportunistic:
exp_alpha = Expected_Alpha_w_Taker
else:
exp_alpha = Expected_Alpha_Net_FR_w_Taker
# MIN_EXPECTED_ALPHA_TO_TRADE = abs(NEXT_NET_FUNDING_RATE)*-1
# MIN_EXPECTED_ALPHA_TO_TRADE = -0.000001 # MIN_EXPECTED_ALPHA_TO_TRADE = -0.000001
# ALPHA RATIO CHECK # ALPHA RATIO CHECK
if not( ( Expected_Alpha_Net_FR_w_Taker > MIN_EXPECTED_ALPHA_TO_TRADE ) or ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS or ALGO_CONFIG.Overrides.Flatten_Open_Positions) ) and Currently_Hedged: if not( ( exp_alpha > MIN_EXPECTED_ALPHA_TO_TRADE ) or ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS or ALGO_CONFIG.Overrides.Flatten_Open_Positions) ) and Currently_Hedged:
# if not( ( Expected_Alpha_Net_FR_w_Taker > MIN_EXPECTED_ALPHA_TO_TRADE ) or ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS or ALGO_CONFIG.Overrides.Flatten_Open_Positions) ) and Currently_Hedged:
if ALGO_CONFIG.Logging.Print_Summary_Each_Loop: if ALGO_CONFIG.Logging.Print_Summary_Each_Loop:
print(f'Alpha Ratio too low ({ALPHA_RATIO:.8f}) and no Open Orders...') print(f'Alpha Ratio too low ({ALPHA_RATIO:.8f}) and no Open Orders...')
elif ( Expected_Alpha_Net_FR_w_Taker <= MIN_EXPECTED_ALPHA_TO_TRADE ) and ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS ) and Currently_Hedged and not(ALGO_CONFIG.Overrides.Flatten_Open_Positions): elif ( Expected_Alpha_Net_FR_w_Taker <= MIN_EXPECTED_ALPHA_TO_TRADE ) and ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS ) and Currently_Hedged and not(ALGO_CONFIG.Overrides.Flatten_Open_Positions):
@@ -732,14 +797,18 @@ async def run_algo():
if ASTER_TGT_TAIL_BASE_QTY == 0.00: if ASTER_TGT_TAIL_BASE_QTY == 0.00:
place_order = False place_order = False
logging.info('ASTER TRYNG TO ORDER 0.00 BASE QTY, SKIPPING') logging.info('ASTER TRYNG TO ORDER 0.00 BASE QTY, SKIPPING')
if place_order: if place_order:
min_price = ASTER.min_price min_price = ASTER.min_price
min_price = int(min_price) if min_price == int(min_price) else min_price min_price = int(min_price) if min_price == int(min_price) else min_price
price: Decimal = Decimal(str(price)).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP) price: Decimal = Decimal(str(price)).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP)
if price == Decimal(str(0.00)).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP):
logging.info('ASTER TRYNG TO ORDER with A PRICE OF 0.00, SKIPPING')
continue
if qty >= ASTER.min_order_size and (qty*price) > ASTER.min_notional:
if qty >= ASTER.min_order_size:
reduceOnly = False reduceOnly = False
else: else:
reduceOnly = True reduceOnly = True
@@ -763,7 +832,7 @@ async def run_algo():
order_resp['order_status'] = order_resp['status'] order_resp['order_status'] = order_resp['status']
ASTER_OPEN_ORDERS.append(order_resp) ASTER_OPEN_ORDERS.append(order_resp)
Just_Rejected_Or_Expired = False Just_Rejected_Or_Expired = False
utils.send_tg_alert(f'FR_ALGO - ASTER Order ({order_resp['orderId']}). Start_$: {ASTER_NOTIONAL_POSITION:.2f}; Value: {float(ASTER_TGT_TAIL_BASE_QTY)*float(price):.2f}; Price: {float(price):.2f}') utils.send_tg_alert(f'FR_ALGO - ASTER Order ({order_resp['orderId']}). Start_$: {ASTER_NOTIONAL_POSITION:.4f}; Value: {float(ASTER_TGT_TAIL_BASE_QTY)*float(price):.4f}; Price: {float(price):.4f}')
logging.info(f'ASTER ORDER PLACED SUCCESS: {order_resp}') logging.info(f'ASTER ORDER PLACED SUCCESS: {order_resp}')
print_summary(use_logging=True) print_summary(use_logging=True)
else: else:
@@ -777,13 +846,22 @@ async def run_algo():
### Add code to flatten small balances ### Add code to flatten small balances
logging.info('ASTER HAS NO TAIL BUT OPEN ORDERS - CANCELLING OPEN ORDERS') logging.info('ASTER HAS NO TAIL BUT OPEN ORDERS - CANCELLING OPEN ORDERS')
await aster_cancel_all_orders() await aster_cancel_all_orders()
time.sleep(0.1)
# if (float(ALPHA_TGT_NOTIONAL) < float(EXTEND_NOTIONAL_POSITION)) and ((float(EXTEND_NOTIONAL_POSITION) + float(EXTEND_TGT_TAIL)) > float(EXTEND_NOTIONAL_POSITION)):
# EXTEND_TGT_TAIL_ORDERABLE= False
# print('ASTER ordering in the wrong directiion - Should be selling, but its buying - skipping')
# elif (float(ALPHA_TGT_NOTIONAL) > float(EXTEND_NOTIONAL_POSITION)) and ((float(EXTEND_NOTIONAL_POSITION) + float(EXTEND_TGT_TAIL)) < float(EXTEND_NOTIONAL_POSITION)):
# EXTEND_TGT_TAIL_ORDERABLE= False
# print('ASTER ordering in the wrong directiion - Should be buying, but its selling - skipping')
# EXTEND # EXTEND
if EXTEND_TGT_TAIL_ORDERABLE and ALGO_CONFIG.Overrides.Allow_Ordering_Extend: if (EXTEND_TGT_TAIL_ORDERABLE and ALGO_CONFIG.Overrides.Allow_Ordering_Extend):
# if ALGO_CONFIG.Overrides.Allow_Ordering_Extend: # if ALGO_CONFIG.Overrides.Allow_Ordering_Extend:
side = OrderSide.BUY if EXTEND_TGT_TAIL_BASE_QTY > 0.00 else OrderSide.SELL side = OrderSide.BUY if EXTEND_TGT_TAIL_BASE_QTY > 0.00 else OrderSide.SELL
symbol = EXTEND.symbol symbol = EXTEND.symbol
qty = Decimal(value=str(abs(EXTEND_TGT_TAIL_BASE_QTY))) qty = Decimal(value=str(abs(EXTEND_TGT_TAIL_BASE_QTY)))
Time_Since_Last_Aster_Fill_ms = ( datetime.now().timestamp()*1000 ) - Last_Aster_Fill_Time_Ts Time_Since_Last_Aster_Fill_ms = ( datetime.now().timestamp()*1000 ) - Last_Aster_Fill_Time_Ts
min_price = EXTEND.min_price min_price = EXTEND.min_price
min_price = int(min_price) if min_price == int(min_price) else min_price min_price = int(min_price) if min_price == int(min_price) else min_price
@@ -791,10 +869,10 @@ async def run_algo():
post_only = False post_only = False
price: Decimal = Decimal(value=str(EXTEND_TOB_PX - ( float(min_price)*int(ALGO_CONFIG.Config.Price_Worsener_Extend) ) if side == 'BUY' else EXTEND_TOB_PX + ( float(min_price)*int(ALGO_CONFIG.Config.Price_Worsener_Extend) ) )).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP) price: Decimal = Decimal(value=str(EXTEND_TOB_PX - ( float(min_price)*int(ALGO_CONFIG.Config.Price_Worsener_Extend) ) if side == 'BUY' else EXTEND_TOB_PX + ( float(min_price)*int(ALGO_CONFIG.Config.Price_Worsener_Extend) ) )).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP)
else: else:
post_only = True # post_only = True
post_only = False
price: Decimal = Decimal(value=str(EXTEND_TOB_PX)).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP) price: Decimal = Decimal(value=str(EXTEND_TOB_PX)).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP)
if abs( ( float(EXTEND_TGT_TAIL_BASE_QTY)*float(price) ) + EXTEND_NOTIONAL_POSITION ) > ALGO_CONFIG.Config.Max_Target_Notional*ALGO_CONFIG.Config.Max_Order_Over_Notional_Ratio: if abs( ( float(EXTEND_TGT_TAIL_BASE_QTY)*float(price) ) + EXTEND_NOTIONAL_POSITION ) > ALGO_CONFIG.Config.Max_Target_Notional*ALGO_CONFIG.Config.Max_Order_Over_Notional_Ratio:
logging.info(f'TRYING TO ORDER OVER MAX NOTIOANL - EXTEND: {EXTEND_NOTIONAL_POSITION:.2f} + {float(EXTEND_TGT_TAIL_BASE_QTY)*float(price):.2f} (qty: {float(EXTEND_TGT_TAIL_BASE_QTY):.2f}; px: {float(price):.2f})') logging.info(f'TRYING TO ORDER OVER MAX NOTIOANL - EXTEND: {EXTEND_NOTIONAL_POSITION:.2f} + {float(EXTEND_TGT_TAIL_BASE_QTY)*float(price):.2f} (qty: {float(EXTEND_TGT_TAIL_BASE_QTY):.2f}; px: {float(price):.2f})')
await kill_algo() await kill_algo()
@@ -802,28 +880,19 @@ async def run_algo():
open_order_dict = dict(EXTEND_OPEN_ORDERS[0]) open_order_dict = dict(EXTEND_OPEN_ORDERS[0])
open_order_id = str(open_order_dict['external_id']) open_order_id = str(open_order_dict['external_id'])
open_order_px = float(open_order_dict['price']) open_order_px = float(open_order_dict['price'])
open_order_filled_qty = float(open_order_dict['filled_qty'])
if qty >= EXTEND.min_order_size: # if int(qty) == 0:
place_order = True # place_order = False
place_residual_order = False # place_residual_order = False
else: # logging.info(f'EXTEND NOT ORDERING DUE TO NOTIONAL QTY == 0; Filled: {float(open_order_filled_qty):.4f}; Residual: {qty:.4f}')
if int(qty) == 0: # else:
place_order = False # place_order = True
place_residual_order = False # place_residual_order = False
logging.info(f'EXTEND NOT ORDERING DUE TO NOTIONAL QTY == 0; Filled: {float(open_order_filled_qty):.4f}; Residual: {qty:.4f}') # logging.info(f'Ordering RESIDUAL market order for remaining small amount: {qty}')
else:
place_order = True
place_residual_order = True
logging.info(f'Ordering RESIDUAL market order for remaining small amount: {qty}')
else: else:
open_order_id = None open_order_id = None
open_order_px = 0 open_order_px = 0
place_order = True place_order = True
if qty >= EXTEND.min_order_size:
place_residual_order = False
else:
place_residual_order = True
if place_order: if place_order:
price: Decimal = Decimal(str(price)).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP) price: Decimal = Decimal(str(price)).quantize(Decimal(str(min_price)), rounding=ROUND_HALF_UP)
if round(open_order_px - float(price), len(str(min_price)) - 2 ) == 0.00: if round(open_order_px - float(price), len(str(min_price)) - 2 ) == 0.00:
@@ -831,14 +900,13 @@ async def run_algo():
print('EXTEND OPEN ORDER NO PX CHG; SKIPPING') print('EXTEND OPEN ORDER NO PX CHG; SKIPPING')
else: else:
try: try:
if place_residual_order: if abs(float(EXTEND_NOTIONAL_POSITION) + (float(qty)*float(price))) < abs(float(EXTEND_NOTIONAL_POSITION)):
post_only = False
reduce_only = True reduce_only = True
else: else:
# post_only = SEE ABOVE
reduce_only = False reduce_only = False
taker_fee = taker_fee=Decimal("0.00000") if post_only else Decimal("0.00025") # taker_fee = taker_fee=Decimal("0.00000") if post_only else Decimal("0.00025")
taker_fee = Decimal("0.00025")
order_resp: WrappedApiResponse[PlacedOrderModel] = await EXTEND_CLIENT.place_order( order_resp: WrappedApiResponse[PlacedOrderModel] = await EXTEND_CLIENT.place_order(
market_name=symbol, market_name=symbol,
amount_of_synthetic=Decimal(str(qty)), amount_of_synthetic=Decimal(str(qty)),
@@ -846,14 +914,14 @@ async def run_algo():
side=side, side=side,
taker_fee=taker_fee, taker_fee=taker_fee,
previous_order_id=open_order_id, previous_order_id=open_order_id,
post_only=post_only post_only=post_only,
# reduce_only=reduce_only reduce_only=reduce_only
) )
except Exception as e: except Exception as e:
logging.error(f'EXTEND ORDER PLACEMENT FAILED - RESP: {order_resp}')
logging.error(f'EXTEND ORDER PLACEMENT FAILED: {e}') logging.error(f'EXTEND ORDER PLACEMENT FAILED: {e}')
logging.error(f'EXTEND ORDER PLACEMENT FAILED - POSTED: market_name:{symbol}, amount_of_synthetic:{qty}, price:{price}, side:{side},taker_fee:{taker_fee}, previous_order_id:{open_order_id}, post_only:{post_only}; reduce_only:{reduce_only}') logging.error(f'EXTEND ORDER PLACEMENT FAILED - POSTED: market_name:{symbol}, side: {side} amount_of_synthetic:{qty}, price:{price}, side:{side},taker_fee:{taker_fee}, previous_order_id:{open_order_id}, post_only:{post_only}; reduce_only:{reduce_only}')
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
logging.error(f'EXTEND ORDER PLACEMENT FAILED - RESP: {order_resp}')
order_resp_dict = dict(order_resp) order_resp_dict = dict(order_resp)
@@ -888,7 +956,8 @@ async def run_algo():
continue continue
else: else:
time.sleep(ALGO_CONFIG.Config.Loop_Sleep_Sec) time.sleep(ALGO_CONFIG.Config.Loop_Sleep_Sec)
# print(f'_____ End No Open Orders _____ (Algo Engine ms: {(time.time() - loop_start)*1000:.2f}); Sleeping for sec: {ALGO_CONFIG.Config.Loop_Sleep_Sec:.0f}') if ALGO_CONFIG.Logging.Print_Summary_Each_Loop:
print(f'_____ End No Open Orders _____ (Algo Engine ms: {(time.time() - loop_start)*1000:.2f}); Sleeping for sec: {ALGO_CONFIG.Config.Loop_Sleep_Sec:.0f}')
except KeyboardInterrupt: except KeyboardInterrupt:
logging.info('CANCELLING OPEN ORDERS') logging.info('CANCELLING OPEN ORDERS')
@@ -916,23 +985,50 @@ async def main():
VAL_KEY = valkey.Valkey(host='localhost', port=6379, db=0, decode_responses=True) VAL_KEY = valkey.Valkey(host='localhost', port=6379, db=0, decode_responses=True)
engine = create_async_engine('mysql+asyncmy://root:pwd@localhost/fund_rate') engine = create_async_engine('mysql+asyncmy://root:pwd@localhost/fund_rate')
best_symbol_by_exchange: dict = json.loads(s=VAL_KEY.get(name='fr_engine_best_fund_rate_output')) # ty:ignore[invalid-argument-type]
ASTER = structs.Perpetual_Exchange(**best_symbol_by_exchange['ASTER'])
EXTEND = structs.Perpetual_Exchange(**best_symbol_by_exchange['EXTEND'])
await set_comb_open_symbols() await set_comb_open_symbols()
best_symbol_by_exchange: dict = json.loads(s=VAL_KEY.get(name='fr_engine_best_fund_rate_output')) # ty:ignore[invalid-argument-type]
if Open_Symbols: if Open_Symbols:
logging.info(f'OPEN SYMBOLS TO CLOSE: {Open_Symbols}') logging.info(f'OPEN SYMBOLS: {Open_Symbols}')
await get_aster_exch_info(symbol_override=Open_Symbols[0]) master_data = json.loads(s=VAL_KEY.get(name='fr_engine_best_fund_rate_master')) # ty:ignore[invalid-argument-type]
await get_extend_exch_info(symbol_override=Open_Symbols[0]) open_symbol_to_work = Open_Symbols[0]
current_pos_master_ast = [d for d in master_data if d.get('symbol_ext') == open_symbol_to_work][0]
ASTER = structs.Perpetual_Exchange(
mult = int(current_pos_master_ast['max_leverage_ast']),
lh_asset = current_pos_master_ast['lh_asset_ast'],
rh_asset = current_pos_master_ast['rh_asset_ast'],
symbol_asset_separator = '',
initial_funding_rate=float(current_pos_master_ast['funding_rate_ast']),
min_price=float(current_pos_master_ast['min_price_ast']),
min_order_size=float(current_pos_master_ast['min_order_size_ast']),
min_lot_size=float(current_pos_master_ast['min_lot_size_ast']),
min_notional=float(current_pos_master_ast['min_notional_ast']),
)
EXTEND = structs.Perpetual_Exchange(
mult = int(current_pos_master_ast['max_leverage_ext']),
lh_asset = current_pos_master_ast['lh_asset_ext'],
rh_asset = current_pos_master_ast['rh_asset_ext'],
symbol_asset_separator = '-',
initial_funding_rate=float(current_pos_master_ast['funding_rate_ext']),
min_price=float(current_pos_master_ast['min_price_ext']),
min_order_size=float(current_pos_master_ast['min_order_size_ext']),
min_lot_size=float(current_pos_master_ast['min_lot_size_ext']),
min_notional=float(current_pos_master_ast['min_notional_ext']),
)
Open_Symbols.pop(0) Open_Symbols.pop(0)
else:
ASTER = structs.Perpetual_Exchange(**best_symbol_by_exchange['ASTER'])
EXTEND = structs.Perpetual_Exchange(**best_symbol_by_exchange['EXTEND'])
# await get_aster_exch_info(symbol_override=Open_Symbols[0])
# await get_extend_exch_info(symbol_override=Open_Symbols[0])
with open('algo_config.json', mode='r', encoding='utf-8') as file: with open('algo_config.json', mode='r', encoding='utf-8') as file:
ALGO_CONFIG = json.load(file) ALGO_CONFIG = json.load(file)
ALGO_CONFIG = structs.Algo_Config(**ALGO_CONFIG) ALGO_CONFIG = structs.Algo_Config(**ALGO_CONFIG)
ALGO_CONFIG.Config.Max_Target_Notional = float(min([ASTER.mult, EXTEND.mult]) * ALGO_CONFIG.Config.Target_Open_Cash_Position) ALGO_CONFIG.Config.Max_Target_Notional = float(min([ASTER.mult, EXTEND.mult]) * ALGO_CONFIG.Config.Target_Open_Cash_Position)
# logging.info(f'Initial Algo Config: {ALGO_CONFIG}')
VAL_KEY.set(name='fr_orchestrator_output', value=json.dumps(obj=ALGO_CONFIG.model_dump())) VAL_KEY.set(name='fr_orchestrator_output', value=json.dumps(obj=ALGO_CONFIG.model_dump()))
VAL_KEY.set(name='fr_algo_working_symbol', value=json.dumps(obj={'ASTER': asdict(obj=ASTER), 'EXTEND': asdict(obj=EXTEND)})) VAL_KEY.set(name='fr_algo_working_symbol', value=json.dumps(obj={'ASTER': asdict(obj=ASTER), 'EXTEND': asdict(obj=EXTEND)}))

View File

@@ -2,6 +2,7 @@ import requests
from dotenv import load_dotenv from dotenv import load_dotenv
import os import os
import time import time
import logging
import threading import threading
from urllib import parse from urllib import parse
@@ -90,7 +91,7 @@ async def post_authenticated_url(req: dict) -> list | dict:
if method == 'GET': if method == 'GET':
res: requests.Response = requests.get(url=full_url, headers=headers) res: requests.Response = requests.get(url=full_url, headers=headers)
# print(res.status_code, res.text) # logging.warning(res.status_code, res.text)
return res.json() return res.json()
elif method == 'POST': elif method == 'POST':
res: requests.Response = requests.post(url=full_url, headers=headers) res: requests.Response = requests.post(url=full_url, headers=headers)

View File

@@ -28,8 +28,8 @@ LEVERAGE_BY_EXCH: list[Asset_Leverage] = [
Asset_Leverage('ASTER', 'SUI' , 'USDT', 75 , 5_416 ), Asset_Leverage('EXTEND', 'SUI' , 'USD', 50, 500_000 ), Asset_Leverage('ASTER', 'SUI' , 'USDT', 75 , 5_416 ), Asset_Leverage('EXTEND', 'SUI' , 'USD', 50, 500_000 ),
Asset_Leverage('ASTER', 'TRUMP', 'USDT', 10 , 60_000 ), Asset_Leverage('EXTEND', 'TRUMP', 'USD', 25, 400_000 ), Asset_Leverage('ASTER', 'TRUMP', 'USDT', 10 , 60_000 ), Asset_Leverage('EXTEND', 'TRUMP', 'USD', 25, 400_000 ),
Asset_Leverage('ASTER', 'WLFI' , 'USDT', 25 , 104_869), Asset_Leverage('EXTEND', 'WLFI' , 'USD', 10, 250_000 ), Asset_Leverage('ASTER', 'WLFI' , 'USDT', 25 , 104_869), Asset_Leverage('EXTEND', 'WLFI' , 'USD', 10, 250_000 ),
Asset_Leverage('ASTER', 'XAG' , 'USDT', 100, 50_000 ), Asset_Leverage('EXTEND', 'XAG' , 'USD', 10, 1_000_000), # Asset_Leverage('ASTER', 'XAG' , 'USDT', 100, 50_000 ), Asset_Leverage('EXTEND', 'XAG' , 'USD', 10, 1_000_000),
Asset_Leverage('ASTER', 'XAU' , 'USDT', 75 , 2_500 ), Asset_Leverage('EXTEND', 'XAU' , 'USD', 25, 2_000_000), # Asset_Leverage('ASTER', 'XAU' , 'USDT', 75 , 2_500 ), Asset_Leverage('EXTEND', 'XAU' , 'USD', 25, 2_000_000),
Asset_Leverage('ASTER', 'XMR' , 'USDT', 50 , 10_000 ), Asset_Leverage('EXTEND', 'XMR' , 'USD', 25, 400_000 ), Asset_Leverage('ASTER', 'XMR' , 'USDT', 50 , 10_000 ), Asset_Leverage('EXTEND', 'XMR' , 'USD', 25, 400_000 ),
Asset_Leverage('ASTER', 'XPT' , 'USDT', 3 , 30_000 ), Asset_Leverage('EXTEND', 'XPT' , 'USD', 5 , 1_000_000), Asset_Leverage('ASTER', 'XPT' , 'USDT', 3 , 30_000 ), Asset_Leverage('EXTEND', 'XPT' , 'USD', 5 , 1_000_000),
Asset_Leverage('ASTER', 'XRP' , 'USDT', 100, 40_000 ), Asset_Leverage('EXTEND', 'XRP' , 'USD', 50, 500_000 ), Asset_Leverage('ASTER', 'XRP' , 'USDT', 100, 40_000 ), Asset_Leverage('EXTEND', 'XRP' , 'USD', 50, 500_000 ),

View File

@@ -169,6 +169,8 @@ class Perpetual_Exchange:
initial_funding_rate: float = 0 initial_funding_rate: float = 0
min_price: float = 0 min_price: float = 0
min_order_size: float = 0 min_order_size: float = 0
min_lot_size: float = 0
min_notional: float = 0
# async def update(self): # async def update(self):
# await self.Collateral_Updates.update() # await self.Collateral_Updates.update()

619
pnl.ipynb
View File

@@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 109, "execution_count": 1,
"id": "44ff5c50", "id": "44ff5c50",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -33,7 +33,38 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 111, "execution_count": 19,
"id": "d3206fe9",
"metadata": {},
"outputs": [],
"source": [
"start_ts = (round(datetime.now().timestamp()*1000)-(60*60*24*1000))"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "9847869c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Timestamp('2026-05-01 22:56:30.744000')"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.to_datetime(start_ts, unit='ms')"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "ca48e11c", "id": "ca48e11c",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@@ -57,7 +88,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 112, "execution_count": 22,
"id": "ec8f5d67", "id": "ec8f5d67",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -82,7 +113,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 113, "execution_count": 23,
"id": "1cb4869a", "id": "1cb4869a",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -108,7 +139,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 119, "execution_count": 24,
"id": "0ebf54b3", "id": "0ebf54b3",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -140,7 +171,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 120, "execution_count": 25,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@@ -268,194 +299,168 @@
"type": "float" "type": "float"
} }
], ],
"ref": "ba489ddb-f098-469d-8584-5f1564160359", "ref": "4fed1e21-7dd2-454b-b923-48d479d7aa72",
"rows": [ "rows": [
[ [
"0", "0",
"17371700930", "328652716",
"2026-04-30 08:46:33.100000", "2026-05-02 01:00:01.450000",
"FILLED", "FILLED",
"BUY", "BUY",
"0.441", "551.0",
"0.0", "0.0",
"2260.01", "0.9059",
"True", "True",
"2049778331801128960", "2050627894673694720",
"2026-04-30 09:10:12.149000", "2026-05-02 17:26:03.721000",
"FILLED", "FILLED",
"SELL", "SELL",
"0.441", "273.0",
"0.24869", "0.06208",
"2255.7", "0.8957",
"False", "False",
"2260.01", "0.9059",
"2255.7", "0.8957",
"0.441", "551.0",
"0.441", "273.0",
"ASTER", "ASTER",
"-2.1494000000001763", "-2.8466799999999965",
"-0.0019070712076496412" "-0.5101158787853532"
], ],
[ [
"1", "1",
"17372582002", "329066650",
"2026-04-30 13:59:05", "2026-05-02 17:25:57.700000",
"FILLED", "FILLED",
"SELL", "SELL",
"0.439", "277.0",
"0.0", "0.1007726",
"2262.5", "0.9095",
"True", "False",
"2049851052585218048", "2050627894673694720",
"2026-04-30 13:59:15.023000", "2026-05-02 17:26:03.721000",
"FILLED", "FILLED",
"BUY", "SELL",
"0.438", "273.0",
"0.0", "0.06208",
"2261.7", "0.8957",
"True", "False",
"2261.7", "0.8957",
"2262.5", "0.9095",
"0.438", "273.0",
"0.439", "277.0",
"EXTEND", "EXTEND",
"0.35120000000007984", "3.659747399999979",
"0.0026376288252886937" "0.030284701714868006"
], ],
[ [
"2", "2",
"17372999630", "329183551",
"2026-04-30 15:32:12.700000", "2026-05-02 21:42:27.900000",
"FILLED",
"BUY",
"0.438",
"0.0",
"2274.09",
"True",
"2049881470860271616",
"2026-04-30 16:00:02.415000",
"FILLED", "FILLED",
"SELL", "SELL",
"0.438", "273.0",
"0.247886", "0.0",
"2263.7", "0.9126",
"True",
"2050694154048565248",
"2026-05-02 21:49:21.186000",
"FILLED",
"BUY",
"273.0",
"0.062319",
"0.9131",
"False", "False",
"2274.09", "0.9131",
"2263.7", "0.9126",
"0.438", "273.0",
"0.438", "273.0",
"ASTER", "EXTEND",
"-4.798706000000144", "-0.1988190000000153",
"-0.00456886051123762" "-0.0005475851494907951"
], ],
[ [
"3", "3",
"17373094474", "329195229",
"2026-04-30 16:00:02.050000", "2026-05-02 22:08:49.450000",
"FILLED", "FILLED",
"SELL", "BUY",
"0.439", "273.0",
"0.0", "0.0",
"2264.61", "0.9136",
"True", "True",
"2049881470860271616", "2050699055663546368",
"2026-04-30 16:00:02.415000", "2026-05-02 22:08:49.823000",
"FILLED", "FILLED",
"SELL", "SELL",
"0.438", "272.0",
"0.247886", "0.062056",
"2263.7", "0.9123",
"False", "False",
"2263.7", "0.9136",
"2264.61", "0.9123",
"0.438", "273.0",
"0.439", "272.0",
"EXTEND", "ASTER",
"0.15160400000013574", "-0.41565599999999125",
"0.002686019554602488" "-0.005080733627143444"
], ],
[ [
"4", "4",
"17373547036", "329206619",
"2026-04-30 19:06:50.200000", "2026-05-02 22:33:28.550000",
"FILLED",
"BUY",
"0.442",
"0.0",
"2260.48",
"True",
"2049929626042335232",
"2026-04-30 19:11:23.505000",
"FILLED", "FILLED",
"SELL", "SELL",
"0.441", "274.0",
"0.24944", "0.0",
"2262.5", "0.9106",
"False", "True",
"2260.48", "2050705268467499008",
"2262.5", "2026-05-02 22:33:52.752000",
"0.442", "FILLED",
"0.441", "BUY",
"ASTER", "274.0",
"0.641379999999992", "0.0",
"-0.0013708496781846692" "0.9105",
"True",
"0.9105",
"0.9106",
"274.0",
"274.0",
"EXTEND",
"0.027399999999996982",
"0.00010982976386600805"
], ],
[ [
"5", "5",
"17373827670", "329210143",
"2026-04-30 21:48:38.550000", "2026-05-02 22:41:58.300000",
"FILLED", "FILLED",
"SELL", "SELL",
"0.221", "274.0",
"0.0", "0.0",
"2257.17", "0.912",
"True", "True",
"2049969423813185536", "2050707405608058880",
"2026-04-30 21:49:32.034000", "2026-05-02 22:42:05.138000",
"FILLED", "FILLED",
"BUY", "BUY",
"0.22", "274.0",
"0.124041",
"2255.4",
"False",
"2255.4",
"2257.17",
"0.22",
"0.221",
"EXTEND",
"0.26712899999999595",
"0.0053338049287769895"
],
[
"6",
"17373941409",
"2026-04-30 23:01:21.150000",
"FILLED",
"SELL",
"0.221",
"0.0", "0.0",
"2253.58", "0.9117",
"True", "True",
"2049987504752680960", "0.9117",
"2026-04-30 23:03:53.771000", "0.912",
"FILLED", "274.0",
"BUY", "274.0",
"0.221",
"0.0",
"2252.6",
"True",
"2252.6",
"2253.58",
"0.221",
"0.221",
"EXTEND", "EXTEND",
"0.21658000000000402", "0.08220000000002137",
"0.0004350528278434247" "0.0003290556103982722"
] ]
], ],
"shape": { "shape": {
"columns": 23, "columns": 23,
"rows": 7 "rows": 6
} }
}, },
"text/html": [ "text/html": [
@@ -503,227 +508,198 @@
" <tbody>\n", " <tbody>\n",
" <tr>\n", " <tr>\n",
" <th>0</th>\n", " <th>0</th>\n",
" <td>17371700930</td>\n", " <td>328652716</td>\n",
" <td>2026-04-30 08:46:33.100</td>\n", " <td>2026-05-02 01:00:01.450</td>\n",
" <td>FILLED</td>\n", " <td>FILLED</td>\n",
" <td>BUY</td>\n", " <td>BUY</td>\n",
" <td>0.441</td>\n", " <td>551.0</td>\n",
" <td>0.0</td>\n", " <td>0.000000</td>\n",
" <td>2260.01</td>\n", " <td>0.9059</td>\n",
" <td>True</td>\n", " <td>True</td>\n",
" <td>2049778331801128960</td>\n", " <td>2050627894673694720</td>\n",
" <td>2026-04-30 09:10:12.149</td>\n", " <td>2026-05-02 17:26:03.721</td>\n",
" <td>...</td>\n", " <td>...</td>\n",
" <td>0.248690</td>\n", " <td>0.062080</td>\n",
" <td>2255.7</td>\n", " <td>0.8957</td>\n",
" <td>False</td>\n", " <td>False</td>\n",
" <td>2260.01</td>\n", " <td>0.9059</td>\n",
" <td>2255.70</td>\n", " <td>0.8957</td>\n",
" <td>0.441</td>\n", " <td>551.0</td>\n",
" <td>0.441</td>\n", " <td>273.0</td>\n",
" <td>ASTER</td>\n", " <td>ASTER</td>\n",
" <td>-2.149400</td>\n", " <td>-2.846680</td>\n",
" <td>-0.001907</td>\n", " <td>-0.510116</td>\n",
" </tr>\n", " </tr>\n",
" <tr>\n", " <tr>\n",
" <th>1</th>\n", " <th>1</th>\n",
" <td>17372582002</td>\n", " <td>329066650</td>\n",
" <td>2026-04-30 13:59:05.000</td>\n", " <td>2026-05-02 17:25:57.700</td>\n",
" <td>FILLED</td>\n", " <td>FILLED</td>\n",
" <td>SELL</td>\n", " <td>SELL</td>\n",
" <td>0.439</td>\n", " <td>277.0</td>\n",
" <td>0.0</td>\n", " <td>0.100773</td>\n",
" <td>2262.50</td>\n", " <td>0.9095</td>\n",
" <td>True</td>\n", " <td>False</td>\n",
" <td>2049851052585218048</td>\n", " <td>2050627894673694720</td>\n",
" <td>2026-04-30 13:59:15.023</td>\n", " <td>2026-05-02 17:26:03.721</td>\n",
" <td>...</td>\n", " <td>...</td>\n",
" <td>0.000000</td>\n", " <td>0.062080</td>\n",
" <td>2261.7</td>\n", " <td>0.8957</td>\n",
" <td>True</td>\n", " <td>False</td>\n",
" <td>2261.70</td>\n", " <td>0.8957</td>\n",
" <td>2262.50</td>\n", " <td>0.9095</td>\n",
" <td>0.438</td>\n", " <td>273.0</td>\n",
" <td>0.439</td>\n", " <td>277.0</td>\n",
" <td>EXTEND</td>\n", " <td>EXTEND</td>\n",
" <td>0.351200</td>\n", " <td>3.659747</td>\n",
" <td>0.002638</td>\n", " <td>0.030285</td>\n",
" </tr>\n", " </tr>\n",
" <tr>\n", " <tr>\n",
" <th>2</th>\n", " <th>2</th>\n",
" <td>17372999630</td>\n", " <td>329183551</td>\n",
" <td>2026-04-30 15:32:12.700</td>\n", " <td>2026-05-02 21:42:27.900</td>\n",
" <td>FILLED</td>\n", " <td>FILLED</td>\n",
" <td>BUY</td>\n", " <td>SELL</td>\n",
" <td>0.438</td>\n", " <td>273.0</td>\n",
" <td>0.0</td>\n", " <td>0.000000</td>\n",
" <td>2274.09</td>\n", " <td>0.9126</td>\n",
" <td>True</td>\n", " <td>True</td>\n",
" <td>2049881470860271616</td>\n", " <td>2050694154048565248</td>\n",
" <td>2026-04-30 16:00:02.415</td>\n", " <td>2026-05-02 21:49:21.186</td>\n",
" <td>...</td>\n", " <td>...</td>\n",
" <td>0.247886</td>\n", " <td>0.062319</td>\n",
" <td>2263.7</td>\n", " <td>0.9131</td>\n",
" <td>False</td>\n", " <td>False</td>\n",
" <td>2274.09</td>\n", " <td>0.9131</td>\n",
" <td>2263.70</td>\n", " <td>0.9126</td>\n",
" <td>0.438</td>\n", " <td>273.0</td>\n",
" <td>0.438</td>\n", " <td>273.0</td>\n",
" <td>ASTER</td>\n", " <td>EXTEND</td>\n",
" <td>-4.798706</td>\n", " <td>-0.198819</td>\n",
" <td>-0.004569</td>\n", " <td>-0.000548</td>\n",
" </tr>\n", " </tr>\n",
" <tr>\n", " <tr>\n",
" <th>3</th>\n", " <th>3</th>\n",
" <td>17373094474</td>\n", " <td>329195229</td>\n",
" <td>2026-04-30 16:00:02.050</td>\n", " <td>2026-05-02 22:08:49.450</td>\n",
" <td>FILLED</td>\n", " <td>FILLED</td>\n",
" <td>SELL</td>\n", " <td>BUY</td>\n",
" <td>0.439</td>\n", " <td>273.0</td>\n",
" <td>0.0</td>\n", " <td>0.000000</td>\n",
" <td>2264.61</td>\n", " <td>0.9136</td>\n",
" <td>True</td>\n", " <td>True</td>\n",
" <td>2049881470860271616</td>\n", " <td>2050699055663546368</td>\n",
" <td>2026-04-30 16:00:02.415</td>\n", " <td>2026-05-02 22:08:49.823</td>\n",
" <td>...</td>\n", " <td>...</td>\n",
" <td>0.247886</td>\n", " <td>0.062056</td>\n",
" <td>2263.7</td>\n", " <td>0.9123</td>\n",
" <td>False</td>\n", " <td>False</td>\n",
" <td>2263.70</td>\n", " <td>0.9136</td>\n",
" <td>2264.61</td>\n", " <td>0.9123</td>\n",
" <td>0.438</td>\n", " <td>273.0</td>\n",
" <td>0.439</td>\n", " <td>272.0</td>\n",
" <td>EXTEND</td>\n", " <td>ASTER</td>\n",
" <td>0.151604</td>\n", " <td>-0.415656</td>\n",
" <td>0.002686</td>\n", " <td>-0.005081</td>\n",
" </tr>\n", " </tr>\n",
" <tr>\n", " <tr>\n",
" <th>4</th>\n", " <th>4</th>\n",
" <td>17373547036</td>\n", " <td>329206619</td>\n",
" <td>2026-04-30 19:06:50.200</td>\n", " <td>2026-05-02 22:33:28.550</td>\n",
" <td>FILLED</td>\n", " <td>FILLED</td>\n",
" <td>BUY</td>\n", " <td>SELL</td>\n",
" <td>0.442</td>\n", " <td>274.0</td>\n",
" <td>0.0</td>\n", " <td>0.000000</td>\n",
" <td>2260.48</td>\n", " <td>0.9106</td>\n",
" <td>True</td>\n", " <td>True</td>\n",
" <td>2049929626042335232</td>\n", " <td>2050705268467499008</td>\n",
" <td>2026-04-30 19:11:23.505</td>\n", " <td>2026-05-02 22:33:52.752</td>\n",
" <td>...</td>\n", " <td>...</td>\n",
" <td>0.249440</td>\n", " <td>0.000000</td>\n",
" <td>2262.5</td>\n", " <td>0.9105</td>\n",
" <td>False</td>\n", " <td>True</td>\n",
" <td>2260.48</td>\n", " <td>0.9105</td>\n",
" <td>2262.50</td>\n", " <td>0.9106</td>\n",
" <td>0.442</td>\n", " <td>274.0</td>\n",
" <td>0.441</td>\n", " <td>274.0</td>\n",
" <td>ASTER</td>\n", " <td>EXTEND</td>\n",
" <td>0.641380</td>\n", " <td>0.027400</td>\n",
" <td>-0.001371</td>\n", " <td>0.000110</td>\n",
" </tr>\n", " </tr>\n",
" <tr>\n", " <tr>\n",
" <th>5</th>\n", " <th>5</th>\n",
" <td>17373827670</td>\n", " <td>329210143</td>\n",
" <td>2026-04-30 21:48:38.550</td>\n", " <td>2026-05-02 22:41:58.300</td>\n",
" <td>FILLED</td>\n", " <td>FILLED</td>\n",
" <td>SELL</td>\n", " <td>SELL</td>\n",
" <td>0.221</td>\n", " <td>274.0</td>\n",
" <td>0.0</td>\n", " <td>0.000000</td>\n",
" <td>2257.17</td>\n", " <td>0.9120</td>\n",
" <td>True</td>\n", " <td>True</td>\n",
" <td>2049969423813185536</td>\n", " <td>2050707405608058880</td>\n",
" <td>2026-04-30 21:49:32.034</td>\n", " <td>2026-05-02 22:42:05.138</td>\n",
" <td>...</td>\n",
" <td>0.124041</td>\n",
" <td>2255.4</td>\n",
" <td>False</td>\n",
" <td>2255.40</td>\n",
" <td>2257.17</td>\n",
" <td>0.220</td>\n",
" <td>0.221</td>\n",
" <td>EXTEND</td>\n",
" <td>0.267129</td>\n",
" <td>0.005334</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>17373941409</td>\n",
" <td>2026-04-30 23:01:21.150</td>\n",
" <td>FILLED</td>\n",
" <td>SELL</td>\n",
" <td>0.221</td>\n",
" <td>0.0</td>\n",
" <td>2253.58</td>\n",
" <td>True</td>\n",
" <td>2049987504752680960</td>\n",
" <td>2026-04-30 23:03:53.771</td>\n",
" <td>...</td>\n", " <td>...</td>\n",
" <td>0.000000</td>\n", " <td>0.000000</td>\n",
" <td>2252.6</td>\n", " <td>0.9117</td>\n",
" <td>True</td>\n", " <td>True</td>\n",
" <td>2252.60</td>\n", " <td>0.9117</td>\n",
" <td>2253.58</td>\n", " <td>0.9120</td>\n",
" <td>0.221</td>\n", " <td>274.0</td>\n",
" <td>0.221</td>\n", " <td>274.0</td>\n",
" <td>EXTEND</td>\n", " <td>EXTEND</td>\n",
" <td>0.216580</td>\n", " <td>0.082200</td>\n",
" <td>0.000435</td>\n", " <td>0.000329</td>\n",
" </tr>\n", " </tr>\n",
" </tbody>\n", " </tbody>\n",
"</table>\n", "</table>\n",
"<p>7 rows × 23 columns</p>\n", "<p>6 rows × 23 columns</p>\n",
"</div>" "</div>"
], ],
"text/plain": [ "text/plain": [
" order_id_ast timestamp_ts_ast status_ast side_ast filled_qty_ast \\\n", " order_id_ast timestamp_ts_ast status_ast side_ast filled_qty_ast \\\n",
"0 17371700930 2026-04-30 08:46:33.100 FILLED BUY 0.441 \n", "0 328652716 2026-05-02 01:00:01.450 FILLED BUY 551.0 \n",
"1 17372582002 2026-04-30 13:59:05.000 FILLED SELL 0.439 \n", "1 329066650 2026-05-02 17:25:57.700 FILLED SELL 277.0 \n",
"2 17372999630 2026-04-30 15:32:12.700 FILLED BUY 0.438 \n", "2 329183551 2026-05-02 21:42:27.900 FILLED SELL 273.0 \n",
"3 17373094474 2026-04-30 16:00:02.050 FILLED SELL 0.439 \n", "3 329195229 2026-05-02 22:08:49.450 FILLED BUY 273.0 \n",
"4 17373547036 2026-04-30 19:06:50.200 FILLED BUY 0.442 \n", "4 329206619 2026-05-02 22:33:28.550 FILLED SELL 274.0 \n",
"5 17373827670 2026-04-30 21:48:38.550 FILLED SELL 0.221 \n", "5 329210143 2026-05-02 22:41:58.300 FILLED SELL 274.0 \n",
"6 17373941409 2026-04-30 23:01:21.150 FILLED SELL 0.221 \n",
"\n", "\n",
" payed_fee_ast price_ast is_mkt_maker_ast order_id_ext \\\n", " payed_fee_ast price_ast is_mkt_maker_ast order_id_ext \\\n",
"0 0.0 2260.01 True 2049778331801128960 \n", "0 0.000000 0.9059 True 2050627894673694720 \n",
"1 0.0 2262.50 True 2049851052585218048 \n", "1 0.100773 0.9095 False 2050627894673694720 \n",
"2 0.0 2274.09 True 2049881470860271616 \n", "2 0.000000 0.9126 True 2050694154048565248 \n",
"3 0.0 2264.61 True 2049881470860271616 \n", "3 0.000000 0.9136 True 2050699055663546368 \n",
"4 0.0 2260.48 True 2049929626042335232 \n", "4 0.000000 0.9106 True 2050705268467499008 \n",
"5 0.0 2257.17 True 2049969423813185536 \n", "5 0.000000 0.9120 True 2050707405608058880 \n",
"6 0.0 2253.58 True 2049987504752680960 \n",
"\n", "\n",
" timestamp_ts_ext ... payed_fee_ext price_ext is_mkt_maker_ext \\\n", " timestamp_ts_ext ... payed_fee_ext price_ext is_mkt_maker_ext \\\n",
"0 2026-04-30 09:10:12.149 ... 0.248690 2255.7 False \n", "0 2026-05-02 17:26:03.721 ... 0.062080 0.8957 False \n",
"1 2026-04-30 13:59:15.023 ... 0.000000 2261.7 True \n", "1 2026-05-02 17:26:03.721 ... 0.062080 0.8957 False \n",
"2 2026-04-30 16:00:02.415 ... 0.247886 2263.7 False \n", "2 2026-05-02 21:49:21.186 ... 0.062319 0.9131 False \n",
"3 2026-04-30 16:00:02.415 ... 0.247886 2263.7 False \n", "3 2026-05-02 22:08:49.823 ... 0.062056 0.9123 False \n",
"4 2026-04-30 19:11:23.505 ... 0.249440 2262.5 False \n", "4 2026-05-02 22:33:52.752 ... 0.000000 0.9105 True \n",
"5 2026-04-30 21:49:32.034 ... 0.124041 2255.4 False \n", "5 2026-05-02 22:42:05.138 ... 0.000000 0.9117 True \n",
"6 2026-04-30 23:03:53.771 ... 0.000000 2252.6 True \n",
"\n", "\n",
" buy_price sell_price buy_qty sell_qty buy_side per_trade_pnl \\\n", " buy_price sell_price buy_qty sell_qty buy_side per_trade_pnl \\\n",
"0 2260.01 2255.70 0.441 0.441 ASTER -2.149400 \n", "0 0.9059 0.8957 551.0 273.0 ASTER -2.846680 \n",
"1 2261.70 2262.50 0.438 0.439 EXTEND 0.351200 \n", "1 0.8957 0.9095 273.0 277.0 EXTEND 3.659747 \n",
"2 2274.09 2263.70 0.438 0.438 ASTER -4.798706 \n", "2 0.9131 0.9126 273.0 273.0 EXTEND -0.198819 \n",
"3 2263.70 2264.61 0.438 0.439 EXTEND 0.151604 \n", "3 0.9136 0.9123 273.0 272.0 ASTER -0.415656 \n",
"4 2260.48 2262.50 0.442 0.441 ASTER 0.641380 \n", "4 0.9105 0.9106 274.0 274.0 EXTEND 0.027400 \n",
"5 2255.40 2257.17 0.220 0.221 EXTEND 0.267129 \n", "5 0.9117 0.9120 274.0 274.0 EXTEND 0.082200 \n",
"6 2252.60 2253.58 0.221 0.221 EXTEND 0.216580 \n",
"\n", "\n",
" per_trade_pnl_pct \n", " per_trade_pnl_pct \n",
"0 -0.001907 \n", "0 -0.510116 \n",
"1 0.002638 \n", "1 0.030285 \n",
"2 -0.004569 \n", "2 -0.000548 \n",
"3 0.002686 \n", "3 -0.005081 \n",
"4 -0.001371 \n", "4 0.000110 \n",
"5 0.005334 \n", "5 0.000329 \n",
"6 0.000435 \n",
"\n", "\n",
"[7 rows x 23 columns]" "[6 rows x 23 columns]"
] ]
}, },
"execution_count": 120, "execution_count": 25,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@@ -734,7 +710,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 116, "execution_count": 18,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@@ -760,17 +736,13 @@
"showlegend": false, "showlegend": false,
"type": "scatter", "type": "scatter",
"x": [ "x": [
"2026-04-30T09:10:12.149000", "2026-05-02T22:08:49.823000",
"2026-04-30T13:59:15.023000", "2026-05-02T22:33:52.752000",
"2026-04-30T16:00:02.415000", "2026-05-02T22:42:05.138000"
"2026-04-30T16:00:02.415000",
"2026-04-30T19:11:23.505000",
"2026-04-30T21:49:32.034000",
"2026-04-30T23:03:53.771000"
], ],
"xaxis": "x", "xaxis": "x",
"y": { "y": {
"bdata": "bS+QoPgxAcA3wZaQD3rWP3d6VPzfMRPAQMD4hsJnwz/J3olZL4bkP+wKtDukGNE/gd17uOS4yz8=", "bdata": "fraYnxua2r+APKTfvg6cP/A1uycPC7U/",
"dtype": "f8" "dtype": "f8"
}, },
"yaxis": "y" "yaxis": "y"
@@ -1608,16 +1580,41 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 27,
"id": "1827a1ca", "id": "1827a1ca",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [
"j = \"[{'timestamp_arrival': 1777762804677, 'timestamp_msg': 1777762804673, 'timestamp_transaction': 1777762804650, 'event_reason_type': 'ORDER', 'symbol': 'LITUSDT', 'position_amount': 0.0, 'entry_price': 0.0, 'accumulated_realized_pre_fees': 2.0749, 'unrealized_pnl': 0.0, 'margin_type': 'cross', 'isolated_wallet': 0.0, 'position_side': 'BOTH'}]\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "77f27d2f",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "6bd8f38d",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "f1a0e1a1",
"metadata": {},
"outputs": [],
"source": [] "source": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"id": "a0380428",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [] "source": []