update switching fr logic for expected alpha
This commit is contained in:
23
algo.ipynb
23
algo.ipynb
@@ -2,7 +2,7 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"execution_count": 1,
|
||||
"id": "d1eed397",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"execution_count": 2,
|
||||
"id": "c6151613",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -32,7 +32,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"execution_count": null,
|
||||
"id": "d83c61e5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -48,6 +48,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"config_update = {\n",
|
||||
" # 'Config': {\n",
|
||||
" # 'Price_Worsener_Aster': 0,\n",
|
||||
@@ -57,15 +58,15 @@
|
||||
" # },\n",
|
||||
" 'Logging': {\n",
|
||||
" 'Log_Summary_Each_Loop': False,\n",
|
||||
" 'Print_Summary_Each_Loop': True,\n",
|
||||
" },\n",
|
||||
" 'Overrides': {\n",
|
||||
" 'Allow_Ordering_Aster': True,\n",
|
||||
" 'Allow_Ordering_Extend': True,\n",
|
||||
" 'Allow_Symbol_Change': True,\n",
|
||||
" # 'Flatten_Open_Positions': False,\n",
|
||||
" # 'Flatten_Open_Positions_Opportunistic': False,\n",
|
||||
" 'Print_Summary_Each_Loop': False,\n",
|
||||
" },\n",
|
||||
" # 'Overrides': {\n",
|
||||
" # 'Allow_Ordering_Aster': True,\n",
|
||||
" # 'Allow_Ordering_Extend': True,\n",
|
||||
" # 'Allow_Symbol_Change': True,\n",
|
||||
" # # 'Flatten_Open_Positions': False,\n",
|
||||
" # # 'Flatten_Open_Positions_Opportunistic': False,\n",
|
||||
" # },\n",
|
||||
"}\n",
|
||||
"VAL_KEY.publish('fr_orchestrator_input', json.dumps(config_update))"
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Updated_Timestamp": 1778133411421,
|
||||
"Updated_Timestamp": 1778178429902,
|
||||
"Config": {
|
||||
"Loop_Sleep_Sec": 0.0,
|
||||
"Max_Order_Over_Notional_Ratio": 1.05,
|
||||
|
||||
@@ -204,8 +204,8 @@ async def loop() -> None:
|
||||
|
||||
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) ]
|
||||
df_best_fr_rate = df_best_fr_rate.loc[( (datetime.now().timestamp()*1000 )-df_best_fr_rate['last_trade_ts_ast']) < (5*60*1000) ] # Last traded in 3min
|
||||
# df_best_fr_rate = df_best_fr_rate.loc[( (datetime.now().timestamp()*1000 )-df_best_fr_rate['last_trade_ts_ext']) < (15*60*1000) ] # Last traded in 15min
|
||||
|
||||
# print(df_best_fr_rate.columns)
|
||||
# print(df_best_fr_rate.iloc[0])
|
||||
|
||||
61
main.py
61
main.py
@@ -249,33 +249,34 @@ def signal_alpha_over_taker(
|
||||
alpha_hurdle_adj: Decimal = Decimal('0.00'),
|
||||
) -> Signal:
|
||||
|
||||
|
||||
if funding_rate_exch == 'ASTER':
|
||||
if funding_rate_side == 'BUY':
|
||||
aster_buy_fund_rate_return = abs(funding_rate)
|
||||
extend_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
else:
|
||||
aster_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
extend_buy_fund_rate_return = abs(funding_rate)
|
||||
else: # funding_rate_exch == 'EXTEND':
|
||||
if funding_rate_side == 'BUY':
|
||||
aster_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
extend_buy_fund_rate_return = abs(funding_rate)
|
||||
else:
|
||||
aster_buy_fund_rate_return = abs(funding_rate)
|
||||
extend_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
|
||||
|
||||
if Config.Overrides.Flatten_Open_Positions_Opportunistic:
|
||||
if Decimal(str(Aster.notional_position)) > 0:
|
||||
aster_buy_fund_rate_return = abs(funding_rate_switch) * -1
|
||||
extend_buy_fund_rate_return = abs(funding_rate_switch)
|
||||
aster_buy_fund_rate_return = aster_buy_fund_rate_return
|
||||
extend_buy_fund_rate_return = max([extend_buy_fund_rate_return, abs(funding_rate_switch)])
|
||||
# funding_rate_exch = 'EXTEND'
|
||||
# funding_rate_side = 'BUY'
|
||||
else: # Decimal(str(Aster.notional_position)) < 0:
|
||||
aster_buy_fund_rate_return = abs(funding_rate_switch)
|
||||
extend_buy_fund_rate_return = abs(funding_rate_switch) * -1
|
||||
aster_buy_fund_rate_return = max([aster_buy_fund_rate_return, abs(funding_rate_switch)])
|
||||
extend_buy_fund_rate_return = extend_buy_fund_rate_return
|
||||
# funding_rate_exch = 'ASTER'
|
||||
# funding_rate_side = 'BUY'
|
||||
else:
|
||||
if funding_rate_exch == 'ASTER':
|
||||
if funding_rate_side == 'BUY':
|
||||
aster_buy_fund_rate_return = abs(funding_rate)
|
||||
extend_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
else:
|
||||
aster_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
extend_buy_fund_rate_return = abs(funding_rate)
|
||||
else: # funding_rate_exch == 'EXTEND':
|
||||
if funding_rate_side == 'BUY':
|
||||
aster_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
extend_buy_fund_rate_return = abs(funding_rate)
|
||||
else:
|
||||
aster_buy_fund_rate_return = abs(funding_rate)
|
||||
extend_buy_fund_rate_return = abs(funding_rate) * -1
|
||||
|
||||
|
||||
aster_mid_px: Decimal = ( Decimal(str(aster_ticker_dict['best_ask_px'])) + Decimal(str(aster_ticker_dict['best_bid_px'])) ) / 2
|
||||
extend_mid_px: Decimal = ( Decimal(str(extend_ticker_dict['best_ask_px'])) + Decimal(str(extend_ticker_dict['best_bid_px'])) ) / 2
|
||||
@@ -288,7 +289,8 @@ def signal_alpha_over_taker(
|
||||
|
||||
aster_buy_expected_alpha: Decimal = ( aster_buy_ratio_min_taker_hurdle - Decimal(str(Aster.buy_ratio)) ).quantize(Decimal('0.000001'), rounding='ROUND_DOWN') # Decimal Price % Diff (x Qty = Alpha $)
|
||||
extend_buy_expected_alpha: Decimal = ( extend_buy_ratio_min_taker_hurdle - Decimal(str(Extend.buy_ratio)) ).quantize(Decimal('0.000001'), rounding='ROUND_DOWN') # Decimal Price % Diff (x Qty = Alpha $)
|
||||
|
||||
best_expected_alpha = max([aster_buy_expected_alpha, extend_buy_expected_alpha])
|
||||
|
||||
# logging.info(f'aster_buy_ratio_min_taker_hurdle: ( {aster_buy_ratio} - {aster_buy_fund_rate_return} ) - {taker_fee} - {alpha_hurdle_adj} = {aster_buy_ratio_min_taker_hurdle}')
|
||||
# logging.info(f'extend_buy_ratio_min_taker_hurdle: ( {extend_buy_ratio} - {extend_buy_fund_rate_return} ) - {taker_fee} - {alpha_hurdle_adj} = {extend_buy_ratio_min_taker_hurdle}')
|
||||
# logging.info(f'aster_buy_expected_alpha: {aster_buy_ratio_min_taker_hurdle} - {Decimal(str(Aster.buy_ratio))} = {aster_buy_expected_alpha}')
|
||||
@@ -299,7 +301,7 @@ def signal_alpha_over_taker(
|
||||
# aster_buy_expected_alpha : 0.000673878630659394266895260 - 0.0014628375 = -0.0007
|
||||
# extend_buy_expected_alpha : -0.001173878630659394266895260 - -0.0014628375 = 0.0002
|
||||
|
||||
if aster_buy_expected_alpha > 0:
|
||||
if ( aster_buy_expected_alpha > 0 ) and ( best_expected_alpha == aster_buy_expected_alpha ):
|
||||
signal: bool = True
|
||||
exchange: str = 'ASTER'
|
||||
side: str = 'BUY'
|
||||
@@ -307,7 +309,7 @@ def signal_alpha_over_taker(
|
||||
expected_alpha: Decimal = aster_buy_expected_alpha
|
||||
model_ratio: Decimal = Decimal(str(Aster.buy_ratio))
|
||||
current_ratio: Decimal = aster_buy_ratio_min_taker_hurdle
|
||||
elif extend_buy_expected_alpha > 0:
|
||||
elif ( extend_buy_expected_alpha > 0 ) and ( best_expected_alpha == extend_buy_expected_alpha ):
|
||||
signal: bool = True
|
||||
exchange: str = 'EXTEND'
|
||||
side: str = 'BUY'
|
||||
@@ -316,7 +318,7 @@ def signal_alpha_over_taker(
|
||||
model_ratio: Decimal = Decimal(str(Extend.buy_ratio))
|
||||
current_ratio: Decimal = extend_buy_ratio_min_taker_hurdle
|
||||
else:
|
||||
if max([aster_buy_expected_alpha,extend_buy_expected_alpha]) == aster_buy_expected_alpha:
|
||||
if best_expected_alpha == aster_buy_expected_alpha:
|
||||
signal: bool = False
|
||||
exchange: str = 'ASTER'
|
||||
side: str = 'BUY'
|
||||
@@ -877,7 +879,7 @@ async def run_algo():
|
||||
aster_fund_rate = aster_fund_rate * -1
|
||||
extend_fund_rate = extend_fund_rate * -1
|
||||
|
||||
aster_fund_rate_time = float(aster_fund_rate_dict.get('next_funding_time_ts_ms', 0))
|
||||
aster_fund_rate_time = max([float(aster_fund_rate_dict.get('next_funding_time_ts_ms', 0)), 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(extend_fund_rate_dict.get('next_funding_time_ts_ms', 0)), 0])
|
||||
@@ -893,7 +895,8 @@ async def run_algo():
|
||||
if next_funding_at_same_time:
|
||||
net_fr = max([fund_rate_ast, fund_rate_ext]) - min([fund_rate_ast, fund_rate_ext])
|
||||
fr_best_exch = 'ASTER' if max([abs(fund_rate_ast), abs(fund_rate_ext)]) == abs(fund_rate_ast) else 'EXTEND'
|
||||
fr_best_side = 'BUY' if net_fr < 0 else 'SELL'
|
||||
fr_best_rate = fund_rate_ast if max([abs(fund_rate_ast), abs(fund_rate_ext)]) == abs(fund_rate_ast) else fund_rate_ext
|
||||
fr_best_side = 'BUY' if fr_best_rate < 0 else 'SELL'
|
||||
return net_fr, fr_best_exch, fr_best_side
|
||||
else:
|
||||
fr_best_exch = 'EXTEND'
|
||||
@@ -1261,11 +1264,7 @@ async def main():
|
||||
VAL_KEY.set(name='fr_orchestrator_output', value=json.dumps(obj=Config.model_dump()))
|
||||
VAL_KEY.set(name='fr_algo_working_symbol', value=json.dumps(obj={'ASTER': asdict(obj=Aster), 'EXTEND': asdict(obj=Extend)}))
|
||||
|
||||
Funding_Rates_Min_Remaining_Factor_Pcts = calc_fr_minutes_remaining_factor(
|
||||
min_start_procedure = 30,
|
||||
min_to_end_procedure = 7,
|
||||
factor_exp_pct = 0.50
|
||||
)
|
||||
Funding_Rates_Min_Remaining_Factor_Pcts = calc_fr_minutes_remaining_factor()
|
||||
|
||||
Algo_Status = structs.Algo_Status(
|
||||
last_update_ts_ms = int(round(datetime.now().timestamp()*1000, 2)),
|
||||
|
||||
75
ng.py
75
ng.py
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
from nicegui import ui, app
|
||||
from nicegui import ui, app, html
|
||||
from sqlalchemy import create_engine
|
||||
# import requests
|
||||
import json
|
||||
@@ -127,7 +127,8 @@ def update_body_scroll(e=None, bool_override=False):
|
||||
async def update_tv():
|
||||
series_update_aster_tob = json.loads(VALKEY.get('fut_ticker_aster')) # ty:ignore[invalid-argument-type]
|
||||
series_update_extend_tob = json.loads(VALKEY.get('fut_ticker_extended')) # ty:ignore[invalid-argument-type]
|
||||
series_update_algo_status = json.loads(VALKEY.get('algo_status')) # ty:ignore[invalid-argument-type]
|
||||
series_update_algo_status = json.loads(VALKEY.get('algo_status')) # ty:ignore[invalid-argument-type]
|
||||
master_data = json.loads(VALKEY.get(name='fr_engine_best_fund_rate_master')) # ty:ignore[invalid-argument-type]
|
||||
|
||||
timestamp_aster_tob = round( ( series_update_aster_tob['timestamp_transaction'] / 1000 ) , 2)
|
||||
timestamp_extend_tob = round( ( series_update_extend_tob['timestamp_msg'] / 1000 ) , 2)
|
||||
@@ -172,18 +173,66 @@ async def rt_chart_page():
|
||||
LOOKBACK = app.storage.user.get('lookback', LOOKBACK)
|
||||
timer = ui.timer(REFRESH_INTERVAL_RT_SEC, update_tv)
|
||||
|
||||
with ui.row():
|
||||
with ui.column():
|
||||
ui.switch('☸︎', value=ALLOW_BODY_SCROLL, on_change=lambda e: update_body_scroll(e))
|
||||
with ui.column():
|
||||
ui.switch('▶️', value=True).bind_value_to(timer, 'active')
|
||||
with ui.column().style('position: absolute; right: 20px; font-family: monospace; align-self: center;'):
|
||||
ui.label('Atwater Trading - Funding Rate')
|
||||
# ui.query('.q-page').classes('flex flex-col h-screen')
|
||||
|
||||
# with ui.row():
|
||||
# with ui.column():
|
||||
# ui.switch('☸︎', value=ALLOW_BODY_SCROLL, on_change=lambda e: update_body_scroll(e))
|
||||
# with ui.column():
|
||||
# ui.switch('▶️', value=True).bind_value_to(timer, 'active')
|
||||
# with ui.column().style('position: absolute; right: 20px; font-family: monospace; align-self: center;'):
|
||||
# ui.label('Atwater Trading - Funding Rate')
|
||||
|
||||
with ui.grid(columns=16).classes('w-full gap-0 auto-fit'):
|
||||
with ui.card().tight().classes('w-full col-span-full no-shadow border border-black-200').style('overflow: auto;'):
|
||||
ui.html('<div id="tv" style="width:100%; height:800px;"></div>', sanitize=False).classes('w-full')
|
||||
ui.run_javascript(f'await create_tv(charts_list={CHARTS}, create_chart_options={CHARTS_OPTIONS});')
|
||||
with ui.grid(columns=2, rows=2).classes('h-screen w-full flex-grow gap-2 auto-fit '):
|
||||
aggrid = ui.aggrid({
|
||||
'columnDefs': [
|
||||
{'field': 'name', 'editable': True, 'sortable': True},
|
||||
{'field': 'age', 'editable': True},
|
||||
{'field': 'id'},
|
||||
],
|
||||
'rowData': [
|
||||
{'id': 0, 'name': 'Alice', 'age': 18},
|
||||
{'id': 1, 'name': 'Bob', 'age': 21},
|
||||
{'id': 2, 'name': 'Carol', 'age': 20},
|
||||
],
|
||||
'rowSelection': {'mode': 'multiRow'},
|
||||
'stopEditingWhenCellsLoseFocus': True,
|
||||
}).classes('auto-fit flex-grow w-full col-span-2 md:col-span-1')
|
||||
# with ui.element(tag='div').classes('auto-fit flex-grow w-full').style("height:100%; width: 100%;"):
|
||||
# with ui.tabs().classes('w-full') as tabs:
|
||||
# one = ui.tab('One').classes('auto-fit flex-grow w-full').style("height:100%; width: 100%;")
|
||||
# two = ui.tab('Two').classes('auto-fit flex-grow w-full').style("height:100%; width: 100%;")
|
||||
# with ui.tab_panels(tabs, value=two).classes('auto-fit flex-grow w-full').style("height:100%; width: 100%;"):
|
||||
# with ui.tab_panel(one).classes('auto-fit flex-grow w-full').style("height:100%; width: 100%;"):
|
||||
# ui.label('First tab')
|
||||
# with ui.tab_panel(two).classes('auto-fit flex-grow w-full').style("height:100%; width: 100%;"):
|
||||
ui.html('<div id="tv" style="height:100%; width: 100%;"></div>', sanitize=False).classes('auto-fit flex-grow w-full col-span-2 md:col-span-1')
|
||||
ui.run_javascript(f'await create_tv(charts_list={CHARTS}, create_chart_options={CHARTS_OPTIONS});')
|
||||
|
||||
with ui.element(tag='div').classes('col-span-2').style("height:100%; width: 100%;"):
|
||||
with ui.tabs().classes('w-full') as tabs:
|
||||
one = ui.tab('One')
|
||||
two = ui.tab('Two')
|
||||
with ui.tab_panels(tabs, value=two).classes('w-full').style("height:100%; width: 100%;"):
|
||||
with ui.tab_panel(one):
|
||||
ui.label('First tab')
|
||||
with ui.tab_panel(two):
|
||||
aggrid_2 = ui.aggrid({
|
||||
'columnDefs': [
|
||||
{'field': 'name', 'editable': True, 'sortable': True},
|
||||
{'field': 'age', 'editable': True},
|
||||
{'field': 'id'},
|
||||
],
|
||||
'rowData': [
|
||||
{'id': 0, 'name': 'Alice', 'age': 18},
|
||||
{'id': 1, 'name': 'Bob', 'age': 21},
|
||||
{'id': 2, 'name': 'Carol', 'age': 20},
|
||||
],
|
||||
'rowSelection': {'mode': 'multiRow'},
|
||||
'stopEditingWhenCellsLoseFocus': True,
|
||||
})
|
||||
|
||||
|
||||
|
||||
def root():
|
||||
app.add_static_files(max_cache_age=0, url_path='/static', local_directory=os.path.join(os.path.dirname(__file__), 'nicegui_modules/static'))
|
||||
|
||||
@@ -36,10 +36,12 @@ async function update_tv(data_list, lookback_max_points) {
|
||||
|
||||
|
||||
async function create_tv(charts_list, create_chart_options) {
|
||||
const container = document.getElementById('tv');
|
||||
|
||||
if (create_chart_options.crosshair == 'NORMAL') {
|
||||
create_chart_options.crosshair = { mode: LightweightCharts.CrosshairMode.Normal }
|
||||
};
|
||||
window.chart = LightweightCharts.createChart(document.getElementById('tv'), create_chart_options);
|
||||
window.chart = LightweightCharts.createChart(container, create_chart_options);
|
||||
window.charts_arr = [];
|
||||
|
||||
charts_list.forEach(function (item, index) {
|
||||
@@ -64,7 +66,18 @@ async function create_tv(charts_list, create_chart_options) {
|
||||
});
|
||||
|
||||
window.chart.timeScale().fitContent();
|
||||
|
||||
|
||||
// Handle responsiveness: Resize chart when container size changes
|
||||
const resizeObserver = new ResizeObserver(entries => {{
|
||||
for (let entry of entries) {{
|
||||
window.chart.applyOptions({
|
||||
width: entry.contentRect.width,
|
||||
height: entry.contentRect.height
|
||||
});
|
||||
}}
|
||||
}});
|
||||
resizeObserver.observe(container);
|
||||
|
||||
console.log("TV Created!")
|
||||
|
||||
// window.midPriceLine_Config = {
|
||||
|
||||
Reference in New Issue
Block a user