refactor algo orchestrator and hedge ratio bug fix
This commit is contained in:
176
main.py
176
main.py
@@ -5,7 +5,6 @@ import math
|
||||
import os
|
||||
import time
|
||||
import traceback
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from decimal import ROUND_DOWN, Decimal
|
||||
from typing import AsyncContextManager
|
||||
@@ -37,24 +36,30 @@ load_dotenv()
|
||||
LOG_FILEPATH: str = os.getenv("LOGS_PATH") + '/Fund_Rate_Algo.log'
|
||||
|
||||
### Algo Config ###
|
||||
ALGO_CONFIG: structs.Algo_Config = None
|
||||
ALGO_CONFIG: structs.Algo_Config | None = None
|
||||
MIN_TIME_TO_FUNDING: int
|
||||
|
||||
### CONSTANTS ###
|
||||
### EXCHANGES ###
|
||||
ASTER = structs.Perpetual_Exchange(
|
||||
mult = 150,
|
||||
lh_asset = 'ETH',
|
||||
rh_asset = 'USDT',
|
||||
symbol_asset_separator = '',
|
||||
)
|
||||
|
||||
EXTEND_LH_ASSET: str = 'ETH'
|
||||
EXTEND_RH_ASSET: str = 'USD'
|
||||
EXTEND_TICKER: str = EXTEND_LH_ASSET + '-' + EXTEND_RH_ASSET
|
||||
EXTEND = structs.Perpetual_Exchange(
|
||||
mult = 50,
|
||||
lh_asset = 'ETH',
|
||||
rh_asset = 'USD',
|
||||
symbol_asset_separator = '-',
|
||||
)
|
||||
|
||||
### GLOBALS ###
|
||||
ASTER_MULT = 150
|
||||
EXTEND_MULT = 50
|
||||
Last_Aster_Fill_Time_Ts: float = 0.00
|
||||
Just_Rejected_Or_Expired: bool = False
|
||||
Best_Symbol_by_Exchange: dict = {}
|
||||
|
||||
# ASTER_MULT = 150
|
||||
# EXTEND_MULT = 50
|
||||
|
||||
ASTER_MIN_ORDER_QTY = 0.001
|
||||
EXTEND_MIN_ORDER_QTY = 0.01
|
||||
@@ -121,7 +126,7 @@ async def get_aster_notional_position(resp: dict | None = None):
|
||||
global ASTER_NOTIONAL_OBJ
|
||||
global ASTER_NOTIONAL_POSITION
|
||||
global ASTER_UNREALIZED_PNL
|
||||
global ASTER_MULT
|
||||
global ASTER
|
||||
|
||||
previous_notional_obj = ASTER_NOTIONAL_OBJ
|
||||
|
||||
@@ -159,32 +164,31 @@ async def get_aster_notional_position(resp: dict | None = None):
|
||||
|
||||
previous_notional_position = ASTER_NOTIONAL_POSITION
|
||||
# if not resp: # this can never evaluate
|
||||
# ASTER_MULT = float(d['leverage'])
|
||||
# if abs(ASTER_NOTIONAL_POSITION) > ALGO_CONFIG.Max_Target_Notional*1.01:
|
||||
if abs(ASTER_NOTIONAL_POSITION) > ALGO_CONFIG.Max_Target_Notional*2.01:
|
||||
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}')
|
||||
# ASTER.mult = float(d['leverage'])
|
||||
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}')
|
||||
await kill_algo()
|
||||
# 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)}')
|
||||
|
||||
async def get_extend_collateral():
|
||||
global EXTEND_AVAIL_COLLATERAL
|
||||
|
||||
get_bals = dict(dict(await EXTEND_CLIENT.account.get_balance()).get('data', {}))
|
||||
EXTEND_AVAIL_COLLATERAL = get_bals.get('available_for_trade', 0) if get_bals.get('collateral_name', None)==EXTEND_RH_ASSET else 0
|
||||
EXTEND_AVAIL_COLLATERAL = get_bals.get('available_for_trade', 0) if get_bals.get('collateral_name', None)==EXTEND.rh_asset else 0
|
||||
|
||||
async def get_extend_notional(resp: dict | None = None):
|
||||
global EXTEND_NOTIONAL_OBJ
|
||||
global EXTEND_NOTIONAL_POSITION
|
||||
global EXTEND_UNREALIZED_PNL
|
||||
global EXTEND_MULT
|
||||
global EXTEND
|
||||
|
||||
previous_notional_obj = EXTEND_NOTIONAL_OBJ
|
||||
previous_notional_position = EXTEND_NOTIONAL_POSITION
|
||||
|
||||
if not resp:
|
||||
resp = dict(await EXTEND_CLIENT.account.get_positions()).get('data', [])
|
||||
pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND_TICKER]
|
||||
pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND.symbol]
|
||||
if pos_dict:
|
||||
pos_dict = pos_dict[0]
|
||||
else:
|
||||
@@ -195,7 +199,7 @@ async def get_extend_notional(resp: dict | None = None):
|
||||
|
||||
pos_dict['timestamp_arrival'] = round(datetime.now().timestamp()*1000)
|
||||
else:
|
||||
pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND_TICKER]
|
||||
pos_dict = [dict(d) for d in resp if dict(d).get('market') == EXTEND.symbol]
|
||||
if pos_dict:
|
||||
pos_dict = pos_dict[0]
|
||||
else:
|
||||
@@ -223,12 +227,12 @@ async def get_extend_notional(resp: dict | None = None):
|
||||
logging.info(f'EXTEND BAD SIDE ON POSITION UPDATE: {pos_dict}')
|
||||
|
||||
EXTEND_NOTIONAL_POSITION = notional_pos_sided - float(EXTEND_UNREALIZED_PNL)
|
||||
EXTEND_MULT = pos_dict.get('leverage', EXTEND_MULT)
|
||||
if abs(EXTEND_NOTIONAL_POSITION) > ALGO_CONFIG.Max_Target_Notional*2.01:
|
||||
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}')
|
||||
EXTEND.mult = pos_dict.get('leverage', EXTEND)
|
||||
if abs(EXTEND_NOTIONAL_POSITION) > ALGO_CONFIG.Config.Max_Target_Notional*ALGO_CONFIG.Config.Max_Order_Over_Notional_Ratio:
|
||||
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()
|
||||
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:.0f}; resp: {bool(resp)}')
|
||||
logging.info(f'EXTEND NOTIONAL CHANGE: {previous_notional_position} -> {EXTEND_NOTIONAL_POSITION:.2f}; UR PNL: {EXTEND_UNREALIZED_PNL:.2f}; MULT: {EXTEND.mult:.0f}; resp: {bool(resp)}')
|
||||
|
||||
### EXCHANGE INFO ###
|
||||
async def get_aster_exch_info():
|
||||
@@ -264,7 +268,7 @@ async def aster_cancel_all_orders():
|
||||
logging.info(f'ASTER CANCEL ALL OPEN ORDERS RESP: {r}')
|
||||
|
||||
async def extend_cancel_all_orders():
|
||||
r = await EXTEND_CLIENT.orders.mass_cancel(markets=[EXTEND_TICKER])
|
||||
r = await EXTEND_CLIENT.orders.mass_cancel(markets=[EXTEND.symbol])
|
||||
logging.info(f'EXTEND CANCEL ALL OPEN ORDERS RESP: {r}')
|
||||
|
||||
### KILL ALGO ###
|
||||
@@ -277,29 +281,39 @@ async def kill_algo():
|
||||
|
||||
### ALGO LOOP ###
|
||||
async def run_algo():
|
||||
global ASTER
|
||||
global EXTEND
|
||||
|
||||
global ALGO_CONFIG
|
||||
global MIN_TIME_TO_FUNDING
|
||||
global ASTER_OPEN_ORDERS
|
||||
global EXTEND_OPEN_ORDERS
|
||||
global Last_Aster_Fill_Time_Ts
|
||||
global Just_Rejected_Or_Expired
|
||||
global Best_Symbol_by_Exchange
|
||||
|
||||
try:
|
||||
while True:
|
||||
loop_start = time.time()
|
||||
# print('__________Start___________')
|
||||
### ALGO CONIFG ###
|
||||
ALGO_CONFIG = json.loads(VAL_KEY.get('fr_orchestrator_output'), object_hook=lambda d: structs.Algo_Config(**d))
|
||||
ALGO_CONFIG.Max_Target_Notional = float(min([ASTER_MULT, EXTEND_MULT]) * ALGO_CONFIG.Target_Open_Cash_Position)
|
||||
|
||||
ALGO_CONFIG = json.loads(VAL_KEY.get('fr_orchestrator_output'))
|
||||
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)
|
||||
|
||||
MIN_TIME_TO_FUNDING = ALGO_CONFIG.Min_Time_To_Funding_Minutes * 60 * 1000
|
||||
MIN_TIME_TO_FUNDING = ALGO_CONFIG.Config.Min_Time_To_Funding_Minutes * 60 * 1000
|
||||
|
||||
### Load Data from Feedhandlers ###
|
||||
Best_Symbol_by_Exchange = json.loads(VAL_KEY.get('fr_engine_best_fund_rate_output'))
|
||||
|
||||
ASTER_FUND_RATE_DICT = json.loads(VAL_KEY.get('fund_rate_aster'))
|
||||
EXTENDED_FUND_RATE_DICT = json.loads(VAL_KEY.get('fund_rate_extended'))
|
||||
|
||||
ASTER_FUND_RATE = float(ASTER_FUND_RATE_DICT.get('funding_rate', 0))
|
||||
EXTEND_FUND_RATE = float(EXTENDED_FUND_RATE_DICT.get('funding_rate', 0))
|
||||
|
||||
if ALGO_CONFIG.Flip_Side_For_Testing:
|
||||
if ALGO_CONFIG.Overrides.Flip_Side_For_Testing:
|
||||
ASTER_FUND_RATE = ASTER_FUND_RATE * -1
|
||||
EXTEND_FUND_RATE = EXTEND_FUND_RATE * -1
|
||||
|
||||
@@ -370,16 +384,20 @@ async def run_algo():
|
||||
if order_update_status in ['CANCELED','EXPIRED']:
|
||||
logging.info(f'ASTER ORDER CANCELLED or EXPIRED: {order_id}')
|
||||
ASTER_OPEN_ORDERS.pop(idx)
|
||||
Just_Rejected_Or_Expired = True
|
||||
utils.send_tg_alert(f'FR_ALGO - ASTER REJECTED ({order_id})')
|
||||
elif order_update_status in ['PARTIALLY_FILLED']:
|
||||
logging.info(f'ASTER ORDER PARTIALLY FILLED: {order_id}')
|
||||
await get_aster_collateral()
|
||||
await get_aster_notional_position()
|
||||
# await get_aster_collateral()
|
||||
await get_aster_notional_position(resp=ASTER_WS_POS_UPDATES)
|
||||
Last_Aster_Fill_Time_Ts = datetime.now().timestamp()*1000
|
||||
utils.send_tg_alert(f'FR_ALGO - ASTER PARTIALLY FILLED ({order_id})')
|
||||
elif order_update_status in ['FILLED']:
|
||||
logging.info(f'ASTER ORDER FILLED: {order_id}')
|
||||
ASTER_OPEN_ORDERS.pop(idx)
|
||||
await get_aster_collateral()
|
||||
await get_aster_notional_position()
|
||||
# await get_aster_collateral()
|
||||
await get_aster_notional_position(resp=ASTER_WS_POS_UPDATES)
|
||||
Last_Aster_Fill_Time_Ts = datetime.now().timestamp()*1000
|
||||
utils.send_tg_alert(f'FR_ALGO - ASTER FILLED ({order_id})')
|
||||
else:
|
||||
logging.critical(f'EXTEND ORDER STATUS CHG TO UNEXPECTED VALUE, KILLING... ({order_id}): {order_orig_status} -> {order_update_status}')
|
||||
@@ -401,6 +419,8 @@ async def run_algo():
|
||||
if order_update_status in ['CANCELLED','EXPIRED','REJECTED']:
|
||||
logging.info(f'EXTEND ORDER CANCELLED, REJECTED or EXPIRED: {order_id}')
|
||||
EXTEND_OPEN_ORDERS.pop(idx)
|
||||
Just_Rejected_Or_Expired = True
|
||||
utils.send_tg_alert(f'FR_ALGO - EXTEND REJECTED ({order_id})')
|
||||
elif order_update_status in ['PARTIALLY_FILLED']:
|
||||
logging.info(f'EXTEND ORDER PARTIALLY FILLED: {order_id}')
|
||||
await get_extend_collateral()
|
||||
@@ -416,10 +436,20 @@ async def run_algo():
|
||||
logging.critical(f'EXTEND ORDER STATUS CHG TO UNEXPECTED VALUE, KILLING... ({order_id}): {order_orig_status} -> {order_update_status}')
|
||||
|
||||
|
||||
# if Best_Symbol_by_Exchange['symbol_aster'] != ASTER.symbol:
|
||||
# if abs( ASTER_NOTIONAL_POSITION ) > 0 or abs( EXTEND_NOTIONAL_POSITION ) > 0:
|
||||
# print('Symbol switch - Flattening Positions')
|
||||
# ALGO_CONFIG.Overrides.Flatten_Open_Positions = True
|
||||
# else:
|
||||
# print(f'Balances Flattened - Updating to Trade New Symbol: ASTER.symbol -> {Best_Symbol_by_Exchange['symbol_aster']}')
|
||||
# # ASTER.symbol = Best_Symbol_by_Exchange['symbol_aster']
|
||||
# # EXTEND.symbol = Best_Symbol_by_Exchange['symbol_extended']
|
||||
|
||||
|
||||
|
||||
min_between_fundings = round((abs(ASTER_FUND_RATE_TIME - EXTEND_FUND_RATE_TIME) / 1000 / 60))
|
||||
FUNDINGS_AT_SAME_TIME_NEXT_HR = min_between_fundings < 5
|
||||
|
||||
|
||||
if ( abs(ASTER_FUND_RATE) > abs(EXTEND_FUND_RATE) ) and FUNDINGS_AT_SAME_TIME_NEXT_HR:
|
||||
ALPHA_EXCH = 'ASTER'
|
||||
ALPHA_FUND_RATE = ASTER_FUND_RATE
|
||||
@@ -429,20 +459,20 @@ async def run_algo():
|
||||
|
||||
if ALPHA_FUND_RATE < 0:
|
||||
ALPHA_CARRY_SIDE = 'BUY'
|
||||
ALPHA_TGT_NOTIONAL = ALGO_CONFIG.Max_Target_Notional
|
||||
ALPHA_TGT_NOTIONAL = ALGO_CONFIG.Config.Max_Target_Notional
|
||||
else:
|
||||
ALPHA_CARRY_SIDE = 'SELL'
|
||||
ALPHA_TGT_NOTIONAL = ALGO_CONFIG.Max_Target_Notional*-1
|
||||
ALPHA_TGT_NOTIONAL = ALGO_CONFIG.Config.Max_Target_Notional*-1
|
||||
|
||||
def calc_next_net_fund_rate(FUNDINGS_AT_SAME_TIME_NEXT_HR: bool) -> float:
|
||||
if FUNDINGS_AT_SAME_TIME_NEXT_HR:
|
||||
return ASTER_FUND_RATE + EXTEND_FUND_RATE
|
||||
return max([ASTER_FUND_RATE, EXTEND_FUND_RATE]) - min([ASTER_FUND_RATE, EXTEND_FUND_RATE])
|
||||
else:
|
||||
return EXTEND_FUND_RATE
|
||||
|
||||
NEXT_NET_FUNDING_RATE = calc_next_net_fund_rate(FUNDINGS_AT_SAME_TIME_NEXT_HR)
|
||||
Flags.NET_FUNDING_IS_ZERO = ( NEXT_NET_FUNDING_RATE >= ( (ALGO_CONFIG.Min_Fund_Rate_Pct_To_Trade*-1) / 100) ) and ( NEXT_NET_FUNDING_RATE <= ( ALGO_CONFIG.Min_Fund_Rate_Pct_To_Trade / 100 ) )
|
||||
if Flags.NET_FUNDING_IS_ZERO or ALGO_CONFIG.Flatten_Open_Positions:
|
||||
Flags.NET_FUNDING_IS_ZERO = ( NEXT_NET_FUNDING_RATE >= ( (ALGO_CONFIG.Config.Min_Fund_Rate_Pct_To_Trade*-1) / 100) ) and ( NEXT_NET_FUNDING_RATE <= ( ALGO_CONFIG.Config.Min_Fund_Rate_Pct_To_Trade / 100 ) )
|
||||
if Flags.NET_FUNDING_IS_ZERO or ALGO_CONFIG.Overrides.Flatten_Open_Positions:
|
||||
ALPHA_TGT_NOTIONAL = 0.00
|
||||
# if ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS:
|
||||
# logging.info('NET FUNDING = 0.00; Cancelling Open Orders! then Waiting...')
|
||||
@@ -507,26 +537,26 @@ async def run_algo():
|
||||
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
|
||||
|
||||
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 ) / ASTER_NOTIONAL_POSITION ) * 100
|
||||
Currently_Hedged = Hedge_Ratio < 1.00
|
||||
|
||||
def print_summary(use_logging: bool = False):
|
||||
OUT: print | logging.info = logging.info if use_logging else print
|
||||
|
||||
OUT(f'''
|
||||
LOOP SLEEP (SEC): {ALGO_CONFIG.Loop_Sleep_Sec}
|
||||
FLIP SIDES FOR TESTING?: {ALGO_CONFIG.Flip_Side_For_Testing}; ASTER ORDER ENABLED? {ALGO_CONFIG.Allow_Ordering_Aster}; EXTEND ORDER ENABLED? {ALGO_CONFIG.Allow_Ordering_Extend}
|
||||
LOOP SLEEP (SEC): {ALGO_CONFIG.Config.Loop_Sleep_Sec}
|
||||
FLIP SIDES FOR TESTING?: {ALGO_CONFIG.Overrides.Flip_Side_For_Testing}; ASTER ORDER ENABLED? {ALGO_CONFIG.Overrides.Allow_Ordering_Aster}; EXTEND ORDER ENABLED? {ALGO_CONFIG.Overrides.Allow_Ordering_Extend}
|
||||
{pd.to_datetime(ASTER_FUND_RATE_TIME, unit='ms')} ({(pd.to_datetime(ASTER_FUND_RATE_TIME, unit='ms')-datetime.now()):}) | {pd.to_datetime(EXTEND_FUND_RATE_TIME, unit='ms')} ({(pd.to_datetime(EXTEND_FUND_RATE_TIME, unit='ms')-datetime.now()):})
|
||||
ASTER: {ASTER_FUND_RATE:.6%} [{ASTER_FUND_RATE*10_000:.2f}bps] [{ASTER_FUND_RATE*1_000_000:.0f}pips] | EXTEND: {EXTEND_FUND_RATE:.6%} [{EXTEND_FUND_RATE*10_000:.2f}bps] [{EXTEND_FUND_RATE*1_000_000:.0f}pips]
|
||||
ASTER: {'LONG PAYS SHORT' if ASTER_FUND_RATE > 0 else 'SHORT PAYS LONG'} | EXTEND: {'LONG PAYS SHORT' if EXTEND_FUND_RATE > 0 else 'SHORT PAYS LONG'}
|
||||
ASTER: [ Available Collateral: {ASTER_AVAIL_COLLATERAL:.4f} ] | EXTEND: [ Available Collateral: {EXTEND_AVAIL_COLLATERAL:.4f} ]
|
||||
ASTER: [ Notional Position $ : {ASTER_NOTIONAL_POSITION:.4f} ] | EXTEND: [ Notional Position $ : {EXTEND_NOTIONAL_POSITION:.4f} ]
|
||||
|
||||
SAME TIME? : {FUNDINGS_AT_SAME_TIME_NEXT_HR} [ Minutes Between Fundings: {min_between_fundings} ]
|
||||
NET FUNDING : {NEXT_NET_FUNDING_RATE:.6%} [{NEXT_NET_FUNDING_RATE*10_000:.2f}bps] [{NEXT_NET_FUNDING_RATE*1_000_000:.0f}pips]; Is Zero?: {Flags.NET_FUNDING_IS_ZERO} [Min: {ALGO_CONFIG.Min_Fund_Rate_Pct_To_Trade}]
|
||||
NET FUNDING : {NEXT_NET_FUNDING_RATE:.6%} [{NEXT_NET_FUNDING_RATE*10_000:.2f}bps] [{NEXT_NET_FUNDING_RATE*1_000_000:.0f}pips]; Is Zero?: {Flags.NET_FUNDING_IS_ZERO} [Min: {ALGO_CONFIG.Config.Min_Fund_Rate_Pct_To_Trade}]
|
||||
ALPHA SIDE : {ALPHA_EXCH} [{ALPHA_CARRY_SIDE}]
|
||||
|
||||
TGT NOTIONAL: $ {abs(ALPHA_TGT_NOTIONAL):.2f}; Flatten Open Positions Flag? {ALGO_CONFIG.Flatten_Open_Positions}
|
||||
TGT NOTIONAL: $ {abs(ALPHA_TGT_NOTIONAL):.2f}; Flatten Open Positions Flag? {ALGO_CONFIG.Overrides.Flatten_Open_Positions}
|
||||
|
||||
ASTER: {ASTER_NOTIONAL_POSITION:.4f} -> {ASTER_TGT_NOTIONAL:.2f} [ Remain: {ASTER_TGT_TAIL:.4f} ] | EXTEND: {EXTEND_NOTIONAL_POSITION:.4f} -> {EXTEND_TGT_NOTIONAL:.2f} [ Remain: {EXTEND_TGT_TAIL:.4f} ]
|
||||
ASTER: {ASTER_TGT_NOTIONAL:.2f} - {ASTER_NOTIONAL_POSITION:.2f} + {ASTER_UNREALIZED_PNL:.2f} = {ASTER_TGT_TAIL:2f} | EXTEND: {EXTEND_TGT_NOTIONAL:.2f} - {EXTEND_NOTIONAL_POSITION:.2f} + {EXTEND_UNREALIZED_PNL:.2f} = {EXTEND_TGT_TAIL:2f}
|
||||
@@ -543,35 +573,38 @@ async def run_algo():
|
||||
--- EXTEND OPEN ORDERS ---
|
||||
{EXTEND_OPEN_ORDERS}
|
||||
''')
|
||||
# ASTER: [ Available Collateral: {ASTER_AVAIL_COLLATERAL:.4f} ] | EXTEND: [ Available Collateral: {EXTEND_AVAIL_COLLATERAL:.4f} ]
|
||||
# Try Making Hedge Order Contingent on Alpha Order Fills (Basically Hedge has to wait for sig Diff in Balance to order.) would improve when extended is thin (Overnight).
|
||||
if ALGO_CONFIG.Log_Summary_Each_Loop:
|
||||
if ALGO_CONFIG.Logging.Log_Summary_Each_Loop:
|
||||
print_summary(use_logging=True)
|
||||
if ALGO_CONFIG.Print_Summary_Each_Loop:
|
||||
if ALGO_CONFIG.Logging.Print_Summary_Each_Loop:
|
||||
print_summary(use_logging=False)
|
||||
# print_summary()
|
||||
|
||||
|
||||
### ROUTES ###
|
||||
# MIN_EXPECTED_ALPHA_TO_TRADE = 0.0001
|
||||
MIN_EXPECTED_ALPHA_TO_TRADE = -0.000001
|
||||
# ALPHA RATIO CHECK
|
||||
if not( ( Expected_Alpha_w_Taker > MIN_EXPECTED_ALPHA_TO_TRADE ) or ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS ) or ALGO_CONFIG.Flatten_Open_Positions ):
|
||||
# logging.info(f'Alpha Ratio too low ({ALPHA_RATIO:.8f}) and no Open Orders...')
|
||||
if not( ( Expected_Alpha_Net_FR_w_Taker > MIN_EXPECTED_ALPHA_TO_TRADE ) or ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS or Just_Rejected_Or_Expired or ALGO_CONFIG.Overrides.Flatten_Open_Positions) ):
|
||||
if ALGO_CONFIG.Logging.Print_Summary_Each_Loop:
|
||||
print(f'Alpha Ratio too low ({ALPHA_RATIO:.8f}) and no Open Orders...')
|
||||
pass
|
||||
elif ( Expected_Alpha_w_Taker <= MIN_EXPECTED_ALPHA_TO_TRADE ) and ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS ) and Currently_Hedged:
|
||||
elif ( Expected_Alpha_Net_FR_w_Taker <= MIN_EXPECTED_ALPHA_TO_TRADE ) and ( ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS ) and Currently_Hedged:
|
||||
await aster_cancel_all_orders()
|
||||
await extend_cancel_all_orders()
|
||||
logging.info('Expected_Alpha went away with open orders...cancelling since we are currently hedged...')
|
||||
time.sleep( (1/1000)*100 ) # 100ms wait for ws cancel response
|
||||
# time.sleep( (1/1000)*100 ) # 100ms wait for ws cancel response
|
||||
else:
|
||||
# logging.info(f'*** Alpha Ratio HIT - LETS ORDER: {ALPHA_RATIO:.8f}')
|
||||
# ASTER
|
||||
if ASTER_TGT_TAIL_ORDERABLE and ALGO_CONFIG.Allow_Ordering_Aster:
|
||||
if ASTER_TGT_TAIL_ORDERABLE and ALGO_CONFIG.Overrides.Allow_Ordering_Aster:
|
||||
symbol = ASTER.symbol
|
||||
side = 'BUY' if ASTER_TGT_TAIL_BASE_QTY > 0.00 else 'SELL'
|
||||
qty = str(abs(ASTER_TGT_TAIL_BASE_QTY))
|
||||
price = ASTER_TOB_PX - ALGO_CONFIG.Price_Worsener_Aster if side == 'BUY' else ASTER_TOB_PX + ALGO_CONFIG.Price_Worsener_Aster
|
||||
price = ASTER_TOB_PX - ALGO_CONFIG.Config.Price_Worsener_Aster if side == 'BUY' else ASTER_TOB_PX + ALGO_CONFIG.Config.Price_Worsener_Aster
|
||||
|
||||
if abs( ( float(ASTER_TGT_TAIL_BASE_QTY)*float(price) ) + ASTER_NOTIONAL_POSITION ) > ALGO_CONFIG.Max_Target_Notional*1.01:
|
||||
if abs( ( float(ASTER_TGT_TAIL_BASE_QTY)*float(price) ) + ASTER_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 - ASTER: {ASTER_NOTIONAL_POSITION} + {float(ASTER_TGT_TAIL_BASE_QTY)*float(price)} (qty: {float(ASTER_TGT_TAIL_BASE_QTY):.2f}; px: {float(price):.2f})')
|
||||
await kill_algo()
|
||||
if ASTER_OPEN_ORDERS:
|
||||
@@ -622,6 +655,7 @@ async def run_algo():
|
||||
order_resp['original_price'] = price
|
||||
order_resp['order_status'] = order_resp['status']
|
||||
ASTER_OPEN_ORDERS.append(order_resp)
|
||||
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}')
|
||||
logging.info(f'ASTER ORDER PLACED SUCCESS: {order_resp}')
|
||||
print_summary(use_logging=True)
|
||||
@@ -634,13 +668,20 @@ async def run_algo():
|
||||
await aster_cancel_all_orders()
|
||||
|
||||
# EXTEND
|
||||
if EXTEND_TGT_TAIL_ORDERABLE and ALGO_CONFIG.Allow_Ordering_Extend:
|
||||
symbol = EXTEND_TICKER
|
||||
if EXTEND_TGT_TAIL_ORDERABLE and ALGO_CONFIG.Overrides.Allow_Ordering_Extend:
|
||||
Time_Since_Last_Aster_Fill_ms = ( datetime.now().timestamp()*1000 ) - Last_Aster_Fill_Time_Ts
|
||||
if Time_Since_Last_Aster_Fill_ms > ( 1000 * ALGO_CONFIG.Config.Switch_To_Taker_Seconds ): # Change to allow taker orders if its been more than x seconds
|
||||
post_only = False
|
||||
price = EXTEND_TOB_PX - ALGO_CONFIG.Config.Price_Worsener_Extend if side == 'BUY' else EXTEND_TOB_PX + ALGO_CONFIG.Config.Price_Worsener_Extend
|
||||
else:
|
||||
post_only = True
|
||||
price = EXTEND_TOB_PX
|
||||
|
||||
symbol = EXTEND.symbol
|
||||
side = OrderSide.BUY if EXTEND_TGT_TAIL_BASE_QTY > 0.00 else OrderSide.SELL
|
||||
qty = Decimal(str(abs(EXTEND_TGT_TAIL_BASE_QTY)))
|
||||
price = EXTEND_TOB_PX - ALGO_CONFIG.Price_Worsener_Extend if side == 'BUY' else EXTEND_TOB_PX + ALGO_CONFIG.Price_Worsener_Extend
|
||||
|
||||
if abs( ( float(EXTEND_TGT_TAIL_BASE_QTY)*float(price) ) + EXTEND_NOTIONAL_POSITION ) > ALGO_CONFIG.Max_Target_Notional*1.01:
|
||||
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})')
|
||||
await kill_algo()
|
||||
if EXTEND_OPEN_ORDERS:
|
||||
@@ -667,17 +708,20 @@ async def run_algo():
|
||||
logging.info('EXTEND OPEN ORDER NO PX CHG; SKIPPING')
|
||||
else:
|
||||
try:
|
||||
taker_fee = taker_fee=Decimal("0.00000") if post_only else Decimal("0.00025")
|
||||
order_resp = await EXTEND_CLIENT.place_order(
|
||||
market_name=symbol,
|
||||
amount_of_synthetic=qty,
|
||||
price=price,
|
||||
side=side,
|
||||
taker_fee=Decimal("0.00025"),
|
||||
taker_fee=taker_fee,
|
||||
previous_order_id=open_order_id,
|
||||
post_only=post_only,
|
||||
)
|
||||
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 - 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}')
|
||||
logging.error(traceback.format_exc())
|
||||
|
||||
order_resp_dict = dict(order_resp)
|
||||
@@ -694,6 +738,7 @@ async def run_algo():
|
||||
order_dict['side'] = str(side)
|
||||
|
||||
EXTEND_OPEN_ORDERS.append(order_dict)
|
||||
Just_Rejected_Or_Expired = False
|
||||
utils.send_tg_alert(f'FR_ALGO - EXTEND Order ({order_dict.get('id', None)}). Start_$: {EXTEND_NOTIONAL_POSITION:.2f}; Value: {float(EXTEND_TGT_TAIL_BASE_QTY)*float(price):.2f}; Price: {float(price):.2f}')
|
||||
logging.info(f'EXTEND ORDER PLACED SUCCESS: {order_dict}')
|
||||
print_summary(use_logging=True)
|
||||
@@ -710,8 +755,8 @@ async def run_algo():
|
||||
if ASTER_OPEN_ORDERS or EXTEND_OPEN_ORDERS:
|
||||
continue
|
||||
else:
|
||||
time.sleep(ALGO_CONFIG.Loop_Sleep_Sec)
|
||||
# print(f'_____ End No Open Orders _____ (Algo Engine ms: {(time.time() - loop_start)*1000:.2f}); Sleeping for sec: {ALGO_CONFIG.Loop_Sleep_Sec:.0f}')
|
||||
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}')
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.info('CANCELLING OPEN ORDERS')
|
||||
@@ -736,10 +781,15 @@ async def main():
|
||||
engine = create_async_engine('mysql+asyncmy://root:pwd@localhost/fund_rate')
|
||||
|
||||
with open('algo_config.json', 'r', encoding='utf-8') as file:
|
||||
ALGO_CONFIG = json.load(file, object_hook=lambda d: structs.Algo_Config(**d))
|
||||
ALGO_CONFIG.Max_Target_Notional = float(min([ASTER_MULT, EXTEND_MULT]) * ALGO_CONFIG.Target_Open_Cash_Position)
|
||||
ALGO_CONFIG = json.load(file)
|
||||
ALGO_CONFIG = structs.Algo_Config(**ALGO_CONFIG)
|
||||
|
||||
VAL_KEY.set('fr_orchestrator_output', json.dumps(asdict(ALGO_CONFIG)))
|
||||
# with open('algo_config.json', 'r', encoding='utf-8') as file:
|
||||
# ALGO_CONFIG = json.load(file, object_hook=lambda d: structs.Algo_Config(**d))
|
||||
|
||||
ALGO_CONFIG.Config.Max_Target_Notional = float(min([ASTER.mult, EXTEND.mult]) * ALGO_CONFIG.Config.Target_Open_Cash_Position)
|
||||
|
||||
VAL_KEY.set('fr_orchestrator_output', json.dumps(ALGO_CONFIG.model_dump()))
|
||||
|
||||
async with engine.connect() as CON:
|
||||
### ASTER SETUP ###
|
||||
|
||||
Reference in New Issue
Block a user