strategy trade counter, gui shortcuts, better log

This commit is contained in:
David Brazda
2023-04-23 17:43:27 +02:00
parent a6e0ac987a
commit 83a7bb77da
16 changed files with 112 additions and 39 deletions

View File

@ -4,7 +4,7 @@ from v2realbot.strategy.base import StrategyState
from v2realbot.strategy.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci from v2realbot.strategy.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide
from v2realbot.indicators.indicators import ema from v2realbot.indicators.indicators import ema
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, dict_replace_value, print from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, dict_replace_value, print, safe_get
from datetime import datetime from datetime import datetime
from icecream import install, ic from icecream import install, ic
#from rich import print #from rich import print
@ -51,6 +51,7 @@ stratvars = AttributeDict(maxpozic = 400,
slope_lookback = 300, slope_lookback = 300,
lookback_offset = 20, lookback_offset = 20,
minimum_slope = -0.05, minimum_slope = -0.05,
first_buy_market = False
) )
##toto rozparsovat a strategii spustit stejne jako v main ##toto rozparsovat a strategii spustit stejne jako v main
toml_string = """ toml_string = """
@ -129,7 +130,12 @@ def next(data, state: StrategyState):
price = last_price price = last_price
state.ilog(e="BUY Vykladame", msg="first price"+str(price) + "pozic:"+str(vykladka), curve=curve, ema=state.indicators.ema[-1], trend=state.vars.Trend, price=price, vykladka=vykladka) state.ilog(e="BUY Vykladame", msg="first price"+str(price) + "pozic:"+str(vykladka), curve=curve, ema=state.indicators.ema[-1], trend=state.vars.Trend, price=price, vykladka=vykladka)
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci ##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci
state.buy_l(price=price, size=qty)
##VAR - na zaklade conf. muzeme jako prvni posilat MARKET
if safe_get(state.vars, "first_buy_market") == True:
state.buy(size=qty)
else:
state.buy_l(price=price, size=qty)
print("prvni limitka na aktuální cenu. Další podle křivky", price, qty) print("prvni limitka na aktuální cenu. Další podle křivky", price, qty)
for i in range(0,vykladka-1): for i in range(0,vykladka-1):
price = price2dec(float(price - curve[i])) price = price2dec(float(price - curve[i]))

View File

@ -43,8 +43,8 @@ from v2realbot.common.model import TradeUpdate, Order
#from rich import print #from rich import print
import threading import threading
import asyncio import asyncio
from v2realbot.config import BT_DELAYS, DATA_DIR, FILL_CONDITION_BUY_LIMIT, FILL_CONDITION_SELL_LIMIT, FILL_LOG_SURROUNDING_TRADES, FILL_CONS_TRADES_REQUIRED from v2realbot.config import BT_DELAYS, DATA_DIR, BT_FILL_CONDITION_BUY_LIMIT, BT_FILL_CONDITION_SELL_LIMIT, BT_FILL_LOG_SURROUNDING_TRADES, BT_FILL_CONS_TRADES_REQUIRED
from v2realbot.utils.utils import AttributeDict, ltp, zoneNY, trunc, count_decimals,print from v2realbot.utils.utils import AttributeDict, ltp, zoneNY, trunc, count_decimals, print
from v2realbot.utils.tlog import tlog from v2realbot.utils.tlog import tlog
from v2realbot.enums.enums import FillCondition from v2realbot.enums.enums import FillCondition
from datetime import datetime, timedelta from datetime import datetime, timedelta
@ -194,7 +194,7 @@ class Backtester:
#TEST zkusime to nemazat, jak ovlivni performance #TEST zkusime to nemazat, jak ovlivni performance
#Mazeme, jinak je to hruza #Mazeme, jinak je to hruza
#nechavame na konci trady, které muzeme potrebovat pro consekutivni pravidlo #nechavame na konci trady, které muzeme potrebovat pro consekutivni pravidlo
del self.btdata[0:index_end-2-FILL_CONS_TRADES_REQUIRED] del self.btdata[0:index_end-2-BT_FILL_CONS_TRADES_REQUIRED]
#ic("after delete",len(self.btdata[0:index_end])) #ic("after delete",len(self.btdata[0:index_end]))
if changes: return 1 if changes: return 1
@ -235,9 +235,9 @@ class Backtester:
#NASTVENI PODMINEK PLNENI #NASTVENI PODMINEK PLNENI
fast_fill_condition = i[1] <= o.limit_price fast_fill_condition = i[1] <= o.limit_price
slow_fill_condition = i[1] < o.limit_price slow_fill_condition = i[1] < o.limit_price
if FILL_CONDITION_BUY_LIMIT == FillCondition.FAST: if BT_FILL_CONDITION_BUY_LIMIT == FillCondition.FAST:
fill_condition = fast_fill_condition fill_condition = fast_fill_condition
elif FILL_CONDITION_BUY_LIMIT == FillCondition.SLOW: elif BT_FILL_CONDITION_BUY_LIMIT == FillCondition.SLOW:
fill_condition = slow_fill_condition fill_condition = slow_fill_condition
else: else:
print("unknow fill condition") print("unknow fill condition")
@ -245,17 +245,17 @@ class Backtester:
if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition: if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition:
consec_cnt += 1 consec_cnt += 1
if consec_cnt == FILL_CONS_TRADES_REQUIRED: if consec_cnt == BT_FILL_CONS_TRADES_REQUIRED:
#(1679081919.381649, 27.88) #(1679081919.381649, 27.88)
ic(i) ic(i)
fill_time = i[0] fill_time = i[0]
fill_price = i[1] fill_price = i[1]
print("FILL LIMIT BUY at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1]) print("FILL LIMIT BUY at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1])
if FILL_LOG_SURROUNDING_TRADES != 0: if BT_FILL_LOG_SURROUNDING_TRADES != 0:
#TODO loguru #TODO loguru
print("FILL SURR TRADES: before",work_range[index-FILL_LOG_SURROUNDING_TRADES:index]) print("FILL SURR TRADES: before",work_range[index-BT_FILL_LOG_SURROUNDING_TRADES:index])
print("FILL SURR TRADES: fill and after",work_range[index:index+FILL_LOG_SURROUNDING_TRADES]) print("FILL SURR TRADES: fill and after",work_range[index:index+BT_FILL_LOG_SURROUNDING_TRADES])
break break
else: else:
consec_cnt = 0 consec_cnt = 0
@ -266,9 +266,9 @@ class Backtester:
#NASTVENI PODMINEK PLNENI #NASTVENI PODMINEK PLNENI
fast_fill_condition = i[1] >= o.limit_price fast_fill_condition = i[1] >= o.limit_price
slow_fill_condition = i[1] > o.limit_price slow_fill_condition = i[1] > o.limit_price
if FILL_CONDITION_SELL_LIMIT == FillCondition.FAST: if BT_FILL_CONDITION_SELL_LIMIT == FillCondition.FAST:
fill_condition = fast_fill_condition fill_condition = fast_fill_condition
elif FILL_CONDITION_SELL_LIMIT == FillCondition.SLOW: elif BT_FILL_CONDITION_SELL_LIMIT == FillCondition.SLOW:
fill_condition = slow_fill_condition fill_condition = slow_fill_condition
else: else:
print("unknown fill condition") print("unknown fill condition")
@ -276,16 +276,16 @@ class Backtester:
if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition: if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition:
consec_cnt += 1 consec_cnt += 1
if consec_cnt == FILL_CONS_TRADES_REQUIRED: if consec_cnt == BT_FILL_CONS_TRADES_REQUIRED:
#(1679081919.381649, 27.88) #(1679081919.381649, 27.88)
ic(i) ic(i)
fill_time = i[0] fill_time = i[0]
fill_price = i[1] fill_price = i[1]
print("FILL LIMIT SELL at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1]) print("FILL LIMIT SELL at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1])
if FILL_LOG_SURROUNDING_TRADES != 0: if BT_FILL_LOG_SURROUNDING_TRADES != 0:
#TODO loguru #TODO loguru
print("FILL SELL SURR TRADES: before",work_range[index-FILL_LOG_SURROUNDING_TRADES:index]) print("FILL SELL SURR TRADES: before",work_range[index-BT_FILL_LOG_SURROUNDING_TRADES:index])
print("FILL SELL SURR TRADES: fill and after",work_range[index:index+FILL_LOG_SURROUNDING_TRADES]) print("FILL SELL SURR TRADES: fill and after",work_range[index:index+BT_FILL_LOG_SURROUNDING_TRADES])
break break
else: else:
consec_cnt = 0 consec_cnt = 0

View File

@ -3,21 +3,21 @@ from v2realbot.enums.enums import Mode, Account, FillCondition
from appdirs import user_data_dir from appdirs import user_data_dir
#how many consecutive trades with the fill price are necessary for LIMIT fill to happen() #how many consecutive trades with the fill price are necessary for LIMIT fill to happen in backtesting
#0 - optimistic, every knot high will fill the order #0 - optimistic, every knot high will fill the order
#N - N consecutive trades required #N - N consecutive trades required
#not impl.yet #not impl.yet
#minimum is 1 #minimum is 1
FILL_CONS_TRADES_REQUIRED = 2 BT_FILL_CONS_TRADES_REQUIRED = 2
#during trade execution logs X-surrounding trades of the one that triggers the fill #during bt trade execution logs X-surrounding trades of the one that triggers the fill
FILL_LOG_SURROUNDING_TRADES = 10 BT_FILL_LOG_SURROUNDING_TRADES = 10
#fill condition for limit order #fill condition for limit order in bt
# fast - price has to be equal or bigger <= # fast - price has to be equal or bigger <=
# slow - price has to be bigger < # slow - price has to be bigger <
FILL_CONDITION_BUY_LIMIT = FillCondition.FAST BT_FILL_CONDITION_BUY_LIMIT = FillCondition.FAST
FILL_CONDITION_SELL_LIMIT = FillCondition.FAST BT_FILL_CONDITION_SELL_LIMIT = FillCondition.FAST
#no print in console #no print in console
QUIET_MODE = False QUIET_MODE = True
#backend counter of api requests #backend counter of api requests
COUNT_API_REQUESTS = False COUNT_API_REQUESTS = False
#stratvars that cannot be changed in gui #stratvars that cannot be changed in gui

View File

@ -222,12 +222,13 @@ def save_history(id: UUID, st: object, runner: Runner, reason: str = None):
#zkousime precist profit z objektu #zkousime precist profit z objektu
try: try:
profit = st.state.profit profit = st.state.profit
trade_count = len(st.tradeList)
except Exception as e: except Exception as e:
profit = str(e) profit = str(e)
for i in db.stratins: for i in db.stratins:
if str(i.id) == str(id): if str(i.id) == str(id):
i.history += "START:"+str(runner.run_started)+"STOP:"+str(runner.run_stopped)+"ACC:"+runner.run_account.value+"M:"+runner.run_mode.value+"PROFIT:"+str(profit)+ "REASON:" + str(reason) i.history += "START:"+str(runner.run_started)+"STOP:"+str(runner.run_stopped)+"ACC:"+runner.run_account.value+"M:"+runner.run_mode.value+"PROFIT:"+str(round(profit,2))+ "TradeCNT:"+str(trade_count) + "REASON:" + str(reason)
#i.history += str(runner.__dict__)+"<BR>" #i.history += str(runner.__dict__)+"<BR>"
db.save() db.save()

View File

@ -12,6 +12,7 @@
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet"> <link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
<script src="/static/js/jquery.dataTables.min.js"></script> <script src="/static/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="/static/main.css"> <link rel="stylesheet" href="/static/main.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js"></script>
</head> </head>
<body> <body>
<div id="main" class="mainConteiner flex-container"> <div id="main" class="mainConteiner flex-container">

View File

@ -1,6 +1,35 @@
API_KEY = localStorage.getItem("api-key") API_KEY = localStorage.getItem("api-key")
//KEY shortcuts
Mousetrap.bind('e', function() {
$( "#button_edit" ).trigger( "click" );
});
Mousetrap.bind('a', function() {
$( "#button_add" ).trigger( "click" );
});
Mousetrap.bind('d', function() {
$( "#button_dup" ).trigger( "click" );
});
Mousetrap.bind('c', function() {
$( "#button_copy" ).trigger( "click" );
});
Mousetrap.bind('r', function() {
$( "#button_run" ).trigger( "click" );
});
Mousetrap.bind('p', function() {
$( "#button_pause" ).trigger( "click" );
});
Mousetrap.bind('s', function() {
$( "#button_stop" ).trigger( "click" );
});
Mousetrap.bind('j', function() {
$( "#button_add_json" ).trigger( "click" );
});
Mousetrap.bind('x', function() {
$( "#button_delete" ).trigger( "click" );
});
//on button //on button
function store_api_key(event) { function store_api_key(event) {
key = document.getElementById("api-key").value; key = document.getElementById("api-key").value;

View File

@ -62,7 +62,7 @@ function connect(event) {
var lines = document.getElementById('lines') var lines = document.getElementById('lines')
var line = document.createElement('div') var line = document.createElement('div')
line.classList.add("line") line.classList.add("line")
const newLine = document.createTextNode("-----------------NEXT ITER------------------") const newLine = document.createTextNode("---------------")
line.appendChild(newLine) line.appendChild(newLine)
lines.appendChild(line) lines.appendChild(line)
@ -84,8 +84,7 @@ function connect(event) {
logcnt++; logcnt++;
row = '<div data-toggle="collapse" data-target="#rec'+logcnt+'">'+logLine.time + " " + logLine.event + ' - '+ logLine.message+'</div>' row = '<div data-toggle="collapse" data-target="#rec'+logcnt+'">'+logLine.time + " " + logLine.event + ' - '+ logLine.message+'</div>'
str_row = JSON.stringify(logLine.details, null, 2) str_row = JSON.stringify(logLine.details, null, 2)
row_detail = '<div id="rec'+logcnt+'" data-toggle="collapse" data-target="#rec'+logcnt+'"class="collapse pidi"><pre>' + str_row + '</pre></div>'
row_detail = '<div id="rec'+logcnt+'" class="collapse pidi"><pre>' + str_row + '</pre></div>'
var lines = document.getElementById('lines') var lines = document.getElementById('lines')
var line = document.createElement('div') var line = document.createElement('div')

View File

@ -1,10 +1,11 @@
from v2realbot.strategy.base import Strategy from v2realbot.strategy.base import Strategy
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial
from v2realbot.utils.tlog import tlog, tlog_exception from v2realbot.utils.tlog import tlog, tlog_exception
from v2realbot.enums.enums import Mode, Order, Account from v2realbot.enums.enums import Mode, Order, Account
from alpaca.trading.models import TradeUpdate from alpaca.trading.models import TradeUpdate
from alpaca.trading.enums import TradeEvent, OrderStatus from alpaca.trading.enums import TradeEvent, OrderStatus
from v2realbot.indicators.indicators import ema from v2realbot.indicators.indicators import ema
import json
#from rich import print #from rich import print
from random import randrange from random import randrange
from alpaca.common.exceptions import APIError from alpaca.common.exceptions import APIError
@ -12,13 +13,15 @@ import copy
from threading import Event from threading import Event
class StrategyOrderLimitVykladaci(Strategy): class StrategyOrderLimitVykladaci(Strategy):
def __init__(self, name: str, symbol: str, next: callable, init: callable, account: Account, mode: Mode = Mode.PAPER, stratvars: AttributeDict = None, open_rush: int = 30, close_rush: int = 30, pe: Event = None, se: Event = None) -> None: def __init__(self, name: str, symbol: str, next: callable, init: callable, account: Account, mode: Mode = Mode.PAPER, stratvars: AttributeDict = None, open_rush: int = 30, close_rush: int = 30, pe: Event = None, se: Event = None) -> None:
super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se) super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se)
async def orderUpdateBuy(self, data: TradeUpdate): async def orderUpdateBuy(self, data: TradeUpdate):
o: Order = data.order o: Order = data.order
self.state.ilog(e="Příchozí BUY notifikace", msg="order status:"+o.status, status=o.status, orderid=str(o.id)) ##nejak to vymyslet, aby se dal poslat cely Trade a serializoval se
self.state.ilog(e="Příchozí BUY notifikace", msg="order status:"+o.status, trade=json.loads(json.dumps(data, default=json_serial)))
if o.status == OrderStatus.FILLED or o.status == OrderStatus.CANCELED: if o.status == OrderStatus.FILLED or o.status == OrderStatus.CANCELED:
#pokud existuje objednavka v pendingbuys - vyhodime ji #pokud existuje objednavka v pendingbuys - vyhodime ji
@ -68,6 +71,7 @@ class StrategyOrderLimitVykladaci(Strategy):
async def orderUpdateSell(self, data: TradeUpdate): async def orderUpdateSell(self, data: TradeUpdate):
self.state.ilog(e="Příchozí SELL notifikace", msg="order status:"+data.order.status, trade=json.loads(json.dumps(data, default=json_serial)))
#PROFIT #PROFIT
#profit pocitame z TradeUpdate.price a TradeUpdate.qty - aktualne provedene mnozstvi a cena #profit pocitame z TradeUpdate.price a TradeUpdate.qty - aktualne provedene mnozstvi a cena
#naklady vypocteme z prumerne ceny, kterou mame v pozicich #naklady vypocteme z prumerne ceny, kterou mame v pozicich
@ -117,19 +121,19 @@ class StrategyOrderLimitVykladaci(Strategy):
def buy(self, size = None, repeat: bool = False): def buy(self, size = None, repeat: bool = False):
print("overriden method to size&check maximum ") print("overriden method to size&check maximum ")
if int(self.state.positions) >= self.state.vars.maxpozic: if int(self.state.positions) >= self.state.vars.maxpozic:
self.state.ilog(e="buy Maxim mnozstvi naplneno", curr_positions=self.state.positions) self.state.ilog(e="buy Maxim mnozstvi naplneno", positions=self.state.positions)
print("max mnostvi naplneno") print("max mnostvi naplneno")
return 0 return 0
if size is None: if size is None:
sizer = self.state.vars.chunk sizer = self.state.vars.chunk
else: else:
sizer = size sizer = size
self.state.blockbuy = 1 self.state.blockbuy = 1
self.state.vars.lastbuyindex = self.state.bars['index'][-1] self.state.vars.lastbuyindex = self.state.bars['index'][-1]
ic(self.state.blockbuy) self.state.ilog(e="send MARKET buy to if", msg="S:"+str(size), ltp=self.state.interface.get_last_price(self.state.symbol))
ic(self.state.vars.lastbuyindex)
return self.state.interface.buy(size=sizer) return self.state.interface.buy(size=sizer)
def buy_l(self, price: float = None, size = None, repeat: bool = False): def buy_l(self, price: float = None, size = None, repeat: bool = False):
print("entering overriden BUY") print("entering overriden BUY")
if int(self.state.positions) >= self.state.vars.maxpozic: if int(self.state.positions) >= self.state.vars.maxpozic:
@ -139,7 +143,7 @@ class StrategyOrderLimitVykladaci(Strategy):
if price is None: price=price2dec((self.state.interface.get_last_price(self.symbol))) if price is None: price=price2dec((self.state.interface.get_last_price(self.symbol)))
ic(price) ic(price)
print("odesilame LIMIT s cenou/qty", price, size) print("odesilame LIMIT s cenou/qty", price, size)
self.state.ilog(e="send buy to if", msg="S:"+str(size)+" P:"+str(price), price=price, size=size) self.state.ilog(e="send LIMIT buy to if", msg="S:"+str(size)+" P:"+str(price), price=price, size=size)
order = self.state.interface.buy_l(price=price, size=size) order = self.state.interface.buy_l(price=price, size=size)
print("ukladame pendingbuys") print("ukladame pendingbuys")
self.state.vars.pendingbuys[str(order)]=price self.state.vars.pendingbuys[str(order)]=price

View File

@ -17,6 +17,8 @@ from v2realbot.interfaces.backtest_interface import BacktestInterface
from v2realbot.interfaces.live_interface import LiveInterface from v2realbot.interfaces.live_interface import LiveInterface
from alpaca.trading.enums import OrderSide from alpaca.trading.enums import OrderSide
from v2realbot.backtesting.backtester import Backtester from v2realbot.backtesting.backtester import Backtester
from alpaca.trading.models import TradeUpdate
from alpaca.trading.enums import TradeEvent, OrderStatus
from threading import Event, current_thread from threading import Event, current_thread
import json import json
@ -48,6 +50,7 @@ class Strategy:
self.account = account self.account = account
self.key = get_key(mode=self.mode, account=self.account) self.key = get_key(mode=self.mode, account=self.account)
self.rtqueue = None self.rtqueue = None
self.tradeList = []
#TODO predelat na dynamické queues #TODO predelat na dynamické queues
@ -308,7 +311,7 @@ class Strategy:
#for order updates from LIVE or BACKTEST #for order updates from LIVE or BACKTEST
#updates are sent only for SYMBOL of strategy #updates are sent only for SYMBOL of strategy
async def order_updates(self, data): async def order_updates(self, data: TradeUpdate):
if self.mode == Mode.LIVE or self.mode == Mode.PAPER: if self.mode == Mode.LIVE or self.mode == Mode.PAPER:
now = datetime.now().timestamp() now = datetime.now().timestamp()
else: else:
@ -316,10 +319,16 @@ class Strategy:
print("NOTIFICATION ARRIVED AT:", now) print("NOTIFICATION ARRIVED AT:", now)
#pokud jde o FILL zapisujeme do self.trades a notifikujeme
if data.event == TradeEvent.FILL:
self.tradeList.append(data)
##TradeUpdate objekt better? ##TradeUpdate objekt better?
order: Order = data.order order: Order = data.order
if order.side == OrderSide.BUY: await self.orderUpdateBuy(data) if order.side == OrderSide.BUY:
if order.side == OrderSide.SELL: await self.orderUpdateSell(data) await self.orderUpdateBuy(data)
if order.side == OrderSide.SELL:
await self.orderUpdateSell(data)
async def orderUpdateBuy(self, data): async def orderUpdateBuy(self, data):
print(data) print(data)

View File

@ -16,6 +16,24 @@ import tomli
from v2realbot.config import DATA_DIR, QUIET_MODE from v2realbot.config import DATA_DIR, QUIET_MODE
import requests import requests
from uuid import UUID from uuid import UUID
from enum import Enum
#from v2realbot.enums.enums import Order
from v2realbot.common.model import Order, TradeUpdate
def safe_get(collection, key, default=None):
"""Get values from a collection without raising errors"""
try:
return collection.get(key, default)
except TypeError:
pass
try:
return collection[key]
except (IndexError, TypeError):
pass
return default
def send_to_telegram(message): def send_to_telegram(message):
apiToken = '5836666362:AAGPuzwp03tczMQTwTBiHW6VsZZ-1RCMAEE' apiToken = '5836666362:AAGPuzwp03tczMQTwTBiHW6VsZZ-1RCMAEE'
@ -38,6 +56,12 @@ def json_serial(obj):
return obj.timestamp() return obj.timestamp()
if isinstance(obj, UUID): if isinstance(obj, UUID):
return str(obj) return str(obj)
if isinstance(obj, Enum):
return str(obj)
if type(obj) is Order:
return obj.__dict__
if type(obj) is TradeUpdate:
return obj.__dict__
raise TypeError (str(obj)+"Type %s not serializable" % type(obj)) raise TypeError (str(obj)+"Type %s not serializable" % type(obj))
def parse_toml_string(tomlst: str): def parse_toml_string(tomlst: str):