start of legs

This commit is contained in:
2026-04-02 02:38:01 +00:00
parent 259ea93479
commit f5d8037594
2 changed files with 237 additions and 127 deletions

348
main.py
View File

@@ -19,7 +19,8 @@ from py_clob_client.clob_types import (
OrderType,
PartialCreateOrderOptions,
PostOrdersArgs,
BalanceAllowanceParams
BalanceAllowanceParams,
OpenOrderParams
)
from py_clob_client.order_builder.constants import BUY, SELL
from sqlalchemy import text
@@ -31,6 +32,7 @@ import modules.api as api
@dataclass
class Custom_OrderArgs(OrderArgs):
max_price: float = 0.00
post_only: bool = False
### Database ###
@@ -45,10 +47,10 @@ LOG_FILEPATH: str = os.getenv("LOGS_PATH") + '/Polymarket_5min_Algo.log'
### ALGO CONFIG / CONSTANTS ###
SLOPE_YES_THRESH = 0.01 # In Percent % Chg (e.g. 0.02 == 0.02%)
ENDTIME_BUFFER_SEC = 30 # Stop trading, cancel all open orders and exit positions this many seconds before mkt settles.
TGT_PX_INDEX_DIFF_THRESH = 0.1 # In Percent % Chg (e.g. 0.02 == 0.02%)
TGT_PX_INDEX_DIFF_THRESH = 0.05 # In Percent % Chg (e.g. 0.02 == 0.02%)
DEFAULT_ORDER_SIZE = 10 # In USDe
MIN_ORDER_SIZE = 5 # In USDe
TGT_PROFIT_CENTS = 0.02
TGT_PROFIT_CENTS = 0.04
CHASE_TO_BUY_CENTS = 0.05
MAX_ALLOWED_POLY_PX = 0.90
@@ -226,9 +228,9 @@ async def slope_decision() -> list[bool, str]:
# print(f'Len Hist : {len(hist_trades[:, 1])}')
# print(f'First Hist : {pd.to_datetime(np.min(hist_trades[:, 0]), unit='ms')}')
# print(f'Latest Hist: {pd.to_datetime(np.max(hist_trades[:, 0]), unit='ms')}')
print(f'Slope Hist Avg: {np.mean(SLOPE_HIST):.4%}')
print(f'Slope Hist Max: {np.max(SLOPE_HIST):.4%}')
print(f'Slope Hist Std: {np.std(SLOPE_HIST):.4%}')
# print(f'Slope Hist Avg: {np.mean(SLOPE_HIST):.4%}')
# print(f'Slope Hist Max: {np.max(SLOPE_HIST):.4%}')
# print(f'Slope Hist Std: {np.std(SLOPE_HIST):.4%}')
slope_1_buy = abs(slope) >= ( SLOPE_YES_THRESH / 100)
slope_5_buy = abs(slope_5) >= ( SLOPE_YES_THRESH / 100)
@@ -263,12 +265,25 @@ async def cancel_single_order_by_id(CLIENT, order_id):
if o.get('orderID') == order_id:
if bool(cxl_resp.get('not_canceled', True)):
if cxl_resp.get('not_canceled', {}).get(order_id, None) == "matched orders can't be canceled":
LOCAL_ACTIVE_ORDERS[idx]['status'] = 'MATCHED'
logging.info(f'Cancel request failed b/c already matched: {cxl_resp}')
return False
return True
elif cxl_resp.get('not_canceled', {}).get(order_id, None) == "order can't be found - already canceled or matched":
logging.info(f'Cancel request failed b/c already matched or cancelled: {cxl_resp}')
LOCAL_ACTIVE_ORDERS.pop(idx)
return False
# GET ORDER STATUS
order_status = CLIENT.get_orders(
OpenOrderParams(id=o['orderID'])
)[0]['status'].upper()
logging.info(f'Fetched status from CLOB: {order_status} for order: {o['orderID']}')
if order_status == 'MATCHED':
logging.info('Order is MATCHED')
return True
elif order_status == 'CANCELED':
logging.info('Order is CANCELED')
LOCAL_ACTIVE_ORDERS.pop(idx)
return False
else:
raise ValueError(f'ORDER CXL FAILED AND ORDER STILL SHOWS AS LIVE: {cxl_resp}; STATUS: {order_status}; ID: {o.get('orderID')}')
else:
logging.warning(f'*** Cancel Request FAILED, shutting down: {cxl_resp}')
raise Exception('*** Cancel Request FAILED - SHUTDONW')
@@ -282,8 +297,12 @@ async def flatten_open_positions(CLIENT, token_id_up, token_id_down):
up = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_up)
down = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_down)
logging.info('*********FLATTENING*********')
logging.info(f'UP BALANCE = {up}')
logging.info(f'DOWN BALANCE = {down}')
### Submit orders to flatten outstanding balances ###
if up > MIN_ORDER_SIZE:
if abs(up) > MIN_ORDER_SIZE:
logging.info(f'Flattening Up Position: {up}')
await post_order(
CLIENT = CLIENT,
@@ -291,12 +310,12 @@ async def flatten_open_positions(CLIENT, token_id_up, token_id_down):
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=token_id_up,
price=float(POLY_CLOB['price'])-0.01,
price=float(POLY_CLOB['price'])-0.05,
size=up,
side=SELL,
)]
)
if down > MIN_ORDER_SIZE:
if abs(down) > MIN_ORDER_SIZE:
logging.info(f'Flattening Down Position: {down}')
await post_order(
CLIENT = CLIENT,
@@ -304,7 +323,7 @@ async def flatten_open_positions(CLIENT, token_id_up, token_id_down):
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=token_id_down,
price=float(POLY_CLOB_DOWN['price'])-0.01,
price=float(POLY_CLOB_DOWN['price'])-0.05,
size=down,
side=SELL,
@@ -354,7 +373,7 @@ async def check_for_open_positions(CLIENT, token_id_up, token_id_down):
return False
@async_timeit
async def post_order(CLIENT, OrderArgs_list: list[Custom_OrderArgs], tick_size: float | str, neg_risk: bool):
async def post_order(CLIENT, OrderArgs_list: list[Custom_OrderArgs], tick_size: float | str, neg_risk: bool) -> list[dict]: # Returns order response dict
global LOCAL_ACTIVE_ORDERS
global LOCAL_TOKEN_BALANCES
@@ -370,7 +389,7 @@ async def post_order(CLIENT, OrderArgs_list: list[Custom_OrderArgs], tick_size:
),
),
orderType=OrderType.GTC,
postOnly=False,
postOnly=oa.post_only,
),
)
@@ -379,7 +398,15 @@ async def post_order(CLIENT, OrderArgs_list: list[Custom_OrderArgs], tick_size:
for idx, d in enumerate(response):
if d['errorMsg'] == '':
d['token_id'] = OrderArgs_list[idx].token_id
if d['token_id'] == POLY_CLOB['token_id_up']:
d['outcome'] = "UP"
elif d['token_id'] == POLY_CLOB['token_id_down']:
d['outcome'] = "DOWN"
else:
d['outcome'] = "UNKNOWN"
d['price'] = OrderArgs_list[idx].price
d['max_price'] = OrderArgs_list[idx].max_price
d['size'] = OrderArgs_list[idx].size
d['side'] = str(OrderArgs_list[idx].side).upper()
@@ -387,8 +414,7 @@ async def post_order(CLIENT, OrderArgs_list: list[Custom_OrderArgs], tick_size:
### Order Immediately Matched, Can Put in Offsetting Order Depending on State ###
print('******** ORDER APPEND TO LOCAL - MATCHED ********* ')
LOCAL_ACTIVE_ORDERS.append(d)
if d['status'].upper() == 'CONFIRMED':
elif d['status'].upper() == 'CONFIRMED':
current_balance = float(LOCAL_TOKEN_BALANCES.get(d['token_id'], 0.00))
if d['side'] == 'BUY':
size = float(d['size'])
@@ -400,15 +426,17 @@ async def post_order(CLIENT, OrderArgs_list: list[Custom_OrderArgs], tick_size:
else:
print('******** ORDER APPEND TO LOCAL - LIVE ********* ')
LOCAL_ACTIVE_ORDERS.append(d)
elif d['errorMsg'] == "invalid post-only order: order crosses book":
logging.info(f'invalid post-only order: order crosses book. posted: {OrderArgs_list[idx].price}')
else:
raise ValueError(f'Order entry failed: {d}')
logging.info(f'Order Posted Resp: {response}')
print(f'Order Posted Resp: {response}')
return response
### Routes ###
async def no_orders_no_positions_route():
async def no_orders(entry_or_exit: str = 'ENTRY'):
global ORDER_LOCK
### Check for Price Bands ###
@@ -427,122 +455,217 @@ async def no_orders_no_positions_route():
logging.info(f'Tgt Diff to Index Outside Limit ({TGT_PX_INDEX_DIFF_THRESH}%); Diff {tgt_px_diff_to_index:.4%}; Index: {ref_px:.2f}; Tgt: {tgt_px:.2f}')
return False
### Check Slope ###
slope_bool, slope_side = await slope_decision()
if not slope_bool:
logging.info('Failed Slope Check')
return False
token_id = POLY_CLOB.get('token_id_up', None) if slope_side=='UP' else POLY_CLOB.get('token_id_down', None)
token_id_up = POLY_CLOB.get('token_id_up', None)
token_id_down = POLY_CLOB.get('token_id_down', None)
### Order Entry ###
px = float(POLY_CLOB['price'])+0.01
order = Custom_OrderArgs(
token_id=token_id,
price=px,
size=DEFAULT_ORDER_SIZE,
side=BUY,
max_price = px + CHASE_TO_BUY_CENTS
if slope_side == 'UP':
if entry_or_exit == 'ENTRY':
side = BUY
size = DEFAULT_ORDER_SIZE
up_px = up_px + 0.01
down_px = down_px - TGT_PROFIT_CENTS
up_post_only = False
down_post_only = False # T
else: # entry_or_exit == 'EXIT'
side = SELL
size = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_up)
up_px = up_px + TGT_PROFIT_CENTS
down_px = down_px - 0.01
up_post_only = False # T
down_post_only = False
else: # slope_side == 'DOWN'
if entry_or_exit == 'ENTRY':
side = BUY
size = DEFAULT_ORDER_SIZE
up_px = up_px - TGT_PROFIT_CENTS
down_px = down_px + 0.01
up_post_only = False # T
down_post_only = False
else:
side = SELL
size = await get_balance_by_token_id(CLIENT=CLIENT, token_id=token_id_up)
up_px = up_px - 0.01
down_px = down_px + TGT_PROFIT_CENTS
up_post_only = False
down_post_only = False # T
buy_up_leg = Custom_OrderArgs(
token_id=token_id_up,
price=up_px,
size=size,
side=side,
max_price = 0.99,
post_only=up_post_only
)
buy_down_leg = Custom_OrderArgs(
token_id=token_id_down,
price=down_px,
size=size,
side=side,
max_price = 0.99,
post_only=down_post_only
)
order_list = [buy_up_leg, buy_down_leg]
### ADD CHECK FOR MKT MOVED AWAY FROM OPPORTNITY ###
if ORDER_LOCK:
logging.info(f'BUY ORDER BLOCKED BY LOCK: {order}')
logging.info(f'BUY ORDER BLOCKED BY LOCK: {order_list}')
else:
logging.info(f'Attempting BUY Order {order}')
logging.info(f'Attempting BUY Order {order_list}')
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [order]
OrderArgs_list = order_list
)
# ORDER_LOCK = ORDER_LOCK + 1
async def active_orders_no_positions_route():
global LOCAL_ACTIVE_ORDERS
if len(LOCAL_ACTIVE_ORDERS) > 2:
logging.critical('More than two active orders, shutting down')
await kill_algo()
b_c = 0
s_c = 0
active_buy_up = False
active_buy_down = False
active_sell_up = False
active_sell_down = False
for o in LOCAL_ACTIVE_ORDERS:
if o['side'] == 'BUY':
if o['token_id']==POLY_CLOB['token_id_up']:
active_buy_up = True
else:
active_buy_down = True
b_c = b_c + 1
elif o['side'] == 'SELL':
if o['token_id']==POLY_CLOB['token_id_up']:
active_sell_up = True
else:
active_sell_down = True
s_c = s_c + 1
if (b_c > 1) or (s_c > 1):
logging.critical(f'More than one active buy or more than one active sell: b_c {b_c}; s_c{s_c}')
if (b_c > 2) or (s_c > 2):
logging.critical(f'More than two active buys or more than two active sells: b_c {b_c}; s_c{s_c}')
await kill_algo()
for o in LOCAL_ACTIVE_ORDERS:
logging.info(f'Working on order ({o['side']}): {o['orderID']}')
if o.get('status').upper() == 'MATCHED':
logging.info('Order is matched, awaiting confirm or kickback')
# logging.info('Order is matched, awaiting confirm or kickback')
if active_buy_up and active_buy_down:
logging.info('BUY UP AND BUY DOWN ACTIVE/MATCHED - WAITING FOR CONFIRMS')
continue
logging.info('Order is matched, ordering inverse side')
order_matched=True
elif o.get('status').upper() == 'FAILED':
order_matched=True
raise ValueError(f'Trade FAILED after matching: {o}')
elif o.get('status').upper() == 'RETRYING':
order_matched=True
raise ValueError(f'Trade RETRYING after matching: {o}')
else:
orig_px = float(o['price'])
orig_size = float(o['size'])
if o['side'] == 'BUY':
if POLY_CLOB['token_id_up'] == o['token_id']:
clob_px = float(POLY_CLOB['price'])
else:
clob_px = float(POLY_CLOB_DOWN['price'])
order_matched = False
if clob_px >= orig_px:
orig_px = float(o['price'])
orig_size = float(o['size'])
### BUY
if o['side'] == 'BUY':
if POLY_CLOB['token_id_up'] == o['token_id']:
clob_px = float(POLY_CLOB['price'])
token_id_inverse = POLY_CLOB['token_id_down']
else:
clob_px = float(POLY_CLOB_DOWN['price'])
token_id_inverse = POLY_CLOB['token_id_up']
if (clob_px >= orig_px) or order_matched:
if (clob_px >= orig_px):
logging.info(f"Market px: ({clob_px} is above buy order px: {orig_px:.2f})")
if o.get('max_price', 0) > clob_px:
if (o.get('max_price', 0) > clob_px) or order_matched:
if (o.get('max_price', 0) > clob_px):
logging.info(f"Market px: ({clob_px} has moved too far away from original target, cancelling and resetting algo: {o.get('max_price', 0) :.2f})")
if not order_matched:
order_matched = await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
if order_matched:
o['status'] = 'MATCHED'
else:
px = orig_px+0.01
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=o['token_id'],
price=px,
size=orig_size,
side=BUY,
max_price=o['max_price']
)]
)
if order_matched:
o['status'] = 'MATCHED'
if order_matched and (not (active_buy_up and active_buy_down)):
logging.info('BUY Order Matched Immediately, Ordering Inverse BUY')
token_id = token_id_inverse
px = 1 - (orig_px+TGT_PROFIT_CENTS)
if clob_px > px:
px = clob_px + 0.01
# max_price = px + CHASE_TO_BUY_CENTS
max_price = px
post_only = False
elif order_matched and (active_buy_up and active_buy_down):
logging.info('BUY UP AND BUY DOWN MATCHED - WAITING FOR CONFIRMS (IN LOOP)')
continue
else:
await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
elif o['side'] == 'SELL':
if POLY_CLOB['token_id_up'] == o['token_id']:
clob_px = float(POLY_CLOB['price'])
token_id = o['token_id']
px = clob_px+0.01
max_price = o['max_price']
post_only = False
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=token_id,
price=px,
size=orig_size,
side=BUY,
max_price=max_price,
post_only=post_only
)]
)
else:
clob_px = float(POLY_CLOB_DOWN['price'])
await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
### SELL
elif o['side'] == 'SELL':
if POLY_CLOB['token_id_up'] == o['token_id']:
clob_px = float(POLY_CLOB['price'])
else:
clob_px = float(POLY_CLOB_DOWN['price'])
if clob_px <= orig_px:
logging.info(f"Market px: ({clob_px} is below sell order px: {orig_px:.2f})")
if clob_px <= orig_px:
logging.info(f"Market px: ({clob_px} is below sell order px: {orig_px:.2f})")
order_filled = await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
if not order_filled:
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=o['token_id'],
price=orig_px-0.01,
size=orig_size,
side=SELL,
max_price = 0.00
)]
)
order_filled = await cancel_single_order_by_id(CLIENT=CLIENT, order_id=o['orderID'])
if not order_filled:
await post_order(
CLIENT = CLIENT,
tick_size = POLY_CLOB['tick_size'],
neg_risk = POLY_CLOB['neg_risk'],
OrderArgs_list = [Custom_OrderArgs(
token_id=o['token_id'],
price=orig_px-0.01,
size=orig_size,
side=SELL,
max_price = 0.00
)]
)
async def no_orders_active_positions_route():
@@ -587,7 +710,7 @@ async def no_orders_active_positions_route():
async def active_orders_active_positions_route():
pass
async def kill_algo():
async def kill_algo(msg: str = 'No kill msg provided'):
logging.info('Killing algo...')
await cancel_all_orders(CLIENT=CLIENT)
await flatten_open_positions(
@@ -595,8 +718,8 @@ async def kill_algo():
token_id_up = POLY_CLOB.get('token_id_up', None),
token_id_down = POLY_CLOB.get('token_id_down', None),
)
logging.info('...algo killed')
raise Exception('Algo Killed')
logging.info(f'...algo killed: {msg}')
raise Exception(f'Algo Killed: {msg}')
async def run_algo():
global POLY_BINANCE
@@ -617,8 +740,13 @@ async def run_algo():
print(f'token_id_up: {POLY_CLOB.get('token_id_up', None)}')
print(f'token_id_down: {POLY_CLOB.get('token_id_down', None)}')
POLY_CLOB = json.loads(VAL_KEY.get('poly_5min_btcusd'))
### Check for missing target px (Poly 5min Target BTC Px Target) ###
if POLY_CLOB.get('target_price', 0) <= 1.00:
kill_algo('')
ACTIVE_BALANCES_EXIST = await check_for_open_positions(
CLIENT=CLIENT,
token_id_up=POLY_CLOB.get('token_id_up', None),
@@ -641,12 +769,13 @@ async def run_algo():
### DO THIS TO AVOID DELAY WITH FILL CONFIRMS
### Manage Local vs User Stream Orders ###
print(f'LOCAL_ACTIVE_ORDERS: {LOCAL_ACTIVE_ORDERS}')
# print(f'LOCAL_ACTIVE_ORDERS: {LOCAL_ACTIVE_ORDERS}')
# print(f'USER_TRADES: {USER_TRADES}')
for idx, o in enumerate(LOCAL_ACTIVE_ORDERS):
user_order = next((item for item in USER_ORDERS if item["id"] == o['orderID']), None)
user_trade = next( ( item for item in USER_TRADES if ( o['orderID'] == item['taker_order_id'] ) or ( o["orderID"] == json.loads(item['maker_orders'])[0]['order_id'] ) ), None )
print(f'USER TRADE: {user_trade}')
print(f'*****USER TRADE: {user_trade}')
if user_trade is not None:
trade_status = str(user_trade['status']).upper()
@@ -676,43 +805,24 @@ async def run_algo():
logging.info('Order FILLED!')
elif trade_status == 'MATCHED':
logging.info(f'Order Matched...awaiting confirm: {trade_status}')
elif trade_status == 'MINED':
logging.info(f'Order Mined ...awaiting confirm: {trade_status}')
else:
logging.info(f'Trade status but not filled: trade= {user_trade}; order={o}')
elif user_order is not None:
order_status = str(user_order['status']).upper()
o['status'] = order_status
logging.info(f'Updated Order Status: {o['status']} --> {order_status}; {o['orderID']}')
# LOCAL_ACTIVE_ORDERS[idx]['status'] = order_status
# if order_status == 'MATCHED':
# LOCAL_ACTIVE_ORDERS.pop(idx)
# token_id = user_order['asset_id']
# current_balance = float(LOCAL_TOKEN_BALANCES.get(token_id, 0.00))
if order_status == 'MATCHED':
logging.info('Order MATCHED, awaiting confirm')
# if user_order['side'] == 'BUY':
# size = float(user_order['size_matched'])
# else:
# size = float(user_order['size_matched']) * -1
# LOCAL_TOKEN_BALANCES[token_id] = current_balance + size
# # px = user_order['price']
# # LOCAL_ACTIVE_POSITIONS.append({
# # 'token_id': token_id,
# # 'order_id': o['orderID'],
# # 'associate_trades': user_order['associate_trades'],
# # 'size_matched': user_order['size_matched'],
# # 'price': px,
# # 'timestamp_value': user_order['timestamp'],
# # })
# logging.info('Order FILLED!')
if order_status == 'CANCELED':
elif order_status == 'CANCELED':
LOCAL_ACTIVE_ORDERS.pop(idx)
logging.info('Order Canceled')
else:
logging.info('Order Live or Trade Awaiting Confirm')
### UPDATES CAN COME THRU EITHER ORDER OR TRADE CHANNELS - NEED TO UPDATE TO HANDLE TRADE CHANNLE
logging.info('Order Live')
token_id_up = POLY_CLOB.get('token_id_up', 0)
token_id_down = POLY_CLOB.get('token_id_down', 0)
@@ -749,7 +859,7 @@ async def run_algo():
### Execution Route ###
if not(LOCAL_ACTIVE_ORDERS) and not(ACTIVE_BALANCES_EXIST): # No Orders, No Positions
print('ROUTE: no_orders_no_positions_route')
await no_orders_no_positions_route()
await no_orders(entry_or_exit='ENTRY')
### Open Orders Route ###
elif LOCAL_ACTIVE_ORDERS and not(ACTIVE_BALANCES_EXIST): # Orders, No Positions
@@ -758,13 +868,13 @@ async def run_algo():
### Open Positions Route ###
elif not(LOCAL_ACTIVE_ORDERS) and ACTIVE_BALANCES_EXIST: # No Orders, Positions
print('ROUTE: no_orders_no_positions_route')
await no_orders_active_positions_route()
print('ROUTE: no_orders_route_active_positions_route')
await no_orders(entry_or_exit='EXIT')
### Open Orders and Open Positions Route ###
else:
print('ROUTE: active_orders_active_positions_route')
await active_orders_no_positions_route() # Orders and Positions
print('ROUTE: active_orders_active_positions_route - OFF')
# await active_orders_no_positions_route() # Orders and Positions
print(f'__________________________ (Algo Engine ms: {(time.time() - loop_start)*1000})')
time.sleep(1)

View File

@@ -299,7 +299,7 @@ async def polymarket_stream():
event_type = data.get('event_type', None)
match event_type:
case 'trade':
logging.info(f'TRADE: {data}')
# logging.info(f'TRADE: {data}')
# trade_status = data.get('status')
# match trade_status: # Raise TELEGRAM ALERT ???
# case 'MATCHED':
@@ -326,9 +326,9 @@ async def polymarket_stream():
LOOKBACK_MIN_TS_MS = ts_arrival-LOCAL_RECENT_TRADES_LOOKBACK_SEC*1000
LOCAL_RECENT_TRADES = [t for t in LOCAL_RECENT_TRADES if t.get('timestamp_arrival', 0) >= LOOKBACK_MIN_TS_MS]
print("---------------------")
print(LOCAL_RECENT_TRADES)
print("---------------------")
# print("---------------------")
# print(LOCAL_RECENT_TRADES)
# print("---------------------")
VAL_KEY_OBJ = json.dumps(LOCAL_RECENT_TRADES)
# VAL_KEY.publish(VK_CHANNEL, VAL_KEY_OBJ)