rozpracovane zmeny

This commit is contained in:
David Brazda
2023-04-19 08:40:02 +02:00
parent e1ce495168
commit 6524b228c4
11 changed files with 277 additions and 22 deletions

7
testy/asyncioRun.py Normal file
View File

@ -0,0 +1,7 @@
import asyncio
async def vysledek():
return 100
a = asyncio.run(vysledek())
print(a)

View File

@ -40,6 +40,7 @@ stratvars = AttributeDict(maxpozic = 250,
lastbuyindex=-6,
pendingbuys={},
limitka = None,
limitka_price = None,
jevylozeno=0,
vykladka=5,
curve = [0.01, 0.01, 0.01, 0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01],
@ -155,10 +156,10 @@ def next(data, state: StrategyState):
slope_lookback = int(state.vars.slope_lookback)
minimum_slope = float(state.vars.minimum_slope)
if len(state.indicators.ema) > slope_lookback:
if len(state.bars.close) > slope_lookback:
#slope = ((state.indicators.ema[-1] - state.indicators.ema[-slope_lookback])/slope_lookback)*100
#PUVODNI slope = ((state.bars.close[-1] - state.bars.close[-slope_lookback])/slope_lookback)*100
slope = ((state.bars.close[-1] - state.indicators.ema[-slope_lookback])/state.indicators.ema[-slope_lookback])*100
slope = ((state.bars.close[-1] - state.bars.close[-slope_lookback])/state.bars.close[-slope_lookback])*100
#roc = ((state.indicators.ema[-1] - state.indicators.ema[-roc_lookback])/state.indicators.ema[-roc_lookback])*100
state.indicators.slope.append(slope)
#state.indicators.roc.append(roc)
@ -166,6 +167,7 @@ def next(data, state: StrategyState):
#ic(state.indicators.roc[-5:])
except Exception as e:
print("Exception in NEXT Indicator section", str(e))
state.ilog(e="EXCEPTION", msg="Exception in NEXT Indicator section" + str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
@ -175,34 +177,54 @@ def next(data, state: StrategyState):
##CONSOLIDATION PART kazdy Nty bar dle nastaveni
if int(data["index"])%int(state.vars.consolidation_bar_count) == 0:
print("***Consolidation ENTRY***")
state.ilog(e="Konzolidujeme")
orderlist = state.interface.get_open_orders(symbol=state.symbol, side=None)
#print(orderlist)
pendingbuys_new = {}
limitka_old = state.vars.limitka
print("Puvodni LIMITKA", limitka_old)
#zaciname s cistym stitem
state.vars.limitka = None
state.vars.limitka_price = None
limitka_found = False
for o in orderlist:
if o.side == OrderSide.SELL:
print("Nalezena LIMITKA")
limitka_found = True
state.vars.limitka = o.id
state.vars.limitka_price = o.limit_price
##TODO sem pridat upravu ceny
if o.side == OrderSide.BUY:
pendingbuys_new[str(o.id)]=float(o.limit_price)
print("Nová LIMITKA", state.vars.limitka)
state.ilog(e="Konzolidace", limitka_old=str(limitka_old), limitka_new=str(state.vars.limitka), limitka_new_price=state.vars.limitka_price)
#neni limitka, ale mela by byt - vytváříme ji
if state.positions > 0 and state.vars.limitka is None:
state.ilog(e="Neni limitka, ale mela by být.")
price=price2dec(float(state.avgp)+state.vars.profit)
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=state.positions))
state.vars.limitka_price = price
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price)
if pendingbuys_new != state.vars.pendingbuys:
state.ilog(e="Rozdilna PB prepsana", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys)
print("ROZDILNA PENDINGBUYS přepsána")
print("OLD",state.vars.pendingbuys)
state.vars.pendingbuys = unpackb(packb(pendingbuys_new))
print("NEW", state.vars.pendingbuys)
else:
print("PENDINGBUYS sedí - necháváme", state.vars.pendingbuys)
state.ilog(e="PB sedi nechavame", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys)
print("OLD jevylozeno", state.vars.jevylozeno)
if len(state.vars.pendingbuys) > 0:
state.vars.jevylozeno = 1
else:
state.vars.jevylozeno = 0
print("NEW jevylozeno", state.vars.jevylozeno)
state.ilog(e="Nove jevyloze", jevylozeno=state.vars.jevylozeno)
#print(limitka)
#print(pendingbuys_new)
@ -215,14 +237,21 @@ def next(data, state: StrategyState):
else:
print("no time for consolidation", data["index"])
#HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru
lp = state.interface.get_last_price(symbol=state.symbol)
state.ilog(e="ITER_ENTRY", last_price=lp, stratvars=state.vars)
#SLOPE ANGLE PROTECTION
state.ilog(e="SLOPE", curr_slope=slope, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-5:])
if slope < minimum_slope:
print("OCHRANA SLOPE TOO HIGH")
state.ilog(e="SLOPE_EXCEEDED")
if len(state.vars.pendingbuys)>0:
print("CANCEL PENDINGBUYS")
ic(state.vars.pendingbuys)
res = asyncio.run(state.cancel_pending_buys())
ic(state.vars.pendingbuys)
state.ilog(e="Rusime pendingbuyes", pb=state.vars.pendingbuys)
print("slope", slope)
print("min slope", minimum_slope)
@ -235,6 +264,7 @@ def next(data, state: StrategyState):
ic(state.time)
#zatim vykladame full
#positions = int(int(state.vars.maxpozic)/int(state.vars.chunk))
state.ilog(e="BUY SIGNAL", ema=state.indicators.ema[-1], trend=state.vars.Trend)
vyloz()
## testuje aktualni cenu od nejvyssi visici limitky
@ -252,6 +282,7 @@ def next(data, state: StrategyState):
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + state.vars.ticks2reset:
print("ujelo to vice nez o " + str(state.vars.ticks2reset) + ", rusime limit buye")
state.ilog(e="Ujelo to o více " + str(state.vars.ticks2reset), msg="rusime PB buye")
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
@ -268,6 +299,7 @@ def next(data, state: StrategyState):
if len(state.vars.pendingbuys) == 0:
state.vars.blockbuy = 0
state.vars.jevylozeno = 0
state.ilog(e="PB se vyklepaly nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno)
#TODO toto dodelat konzolidaci a mozna lock na limitku a pendingbuys a jevylozeno ??
@ -305,6 +337,7 @@ def init(state: StrategyState):
state.indicators['ema'] = []
state.indicators['slope'] = []
#state.indicators['roc'] = []
#state.ilog(e="INIT", stratvars=state.vars)
def main():

View File

@ -113,7 +113,7 @@ async def websocket_endpoint(
if data=="break":
break
await ws.send_text(data)
print("WSTX thread received data", data)
print("WSTX thread received data") #,data)
except Empty:
print("WSTX thread Heartbeat. No data received from queue.")
continue

View File

@ -16,6 +16,30 @@
<body>
<div id="main" class="mainConteiner flex-container">
<div id="chartContainer" class="flex-items">
<div class="line">
<div data-toggle="collapse" data-target="#rec1">12233 <strong>Event</strong></div>
<div id="rec1" class="collapse">
Detaila mozna structured
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</div>
<div class="line">
<div data-toggle="collapse" data-target="#rec2">12233 <strong>Event</strong></div>
<div id="rec2" class="collapse">
Detaila mozna structured
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</div>
<h4>Status: <span id="status">Not connected</span></h4>
<div id="formular">
<form action="">
@ -26,11 +50,16 @@
<button onclick="sendMessage(event)" id="bt.send" class="btn btn-success">Send</button>
</form>
</div>
<ul id='messages'>
</ul>
<div id="chart" style="display: None"></div>
<div id="chart" style="display: None; float: left; "></div>
<div class="legend" id="legend"></div>
<div id="msgContainer">
<div class="msgContainerInner">
<div id="lines">
</div>
</div>
</div>
</div>
<div id="runner-table" class="flex-items">
<div id="controls">
<label>API-KEY: <input type="password" id="api-key" autocomplete="off"/></label>

View File

@ -1,16 +1,18 @@
//const chartOptions = { layout: { textColor: 'black', background: { type: 'solid', color: 'white' } } };
const chartOptions = { width: 1200, height: 600, leftPriceScale: {visible: true}}
const chartOptions = { width: 1045, height: 600, leftPriceScale: {visible: true}}
const chart = LightweightCharts.createChart(document.getElementById('chart'), chartOptions);
chart.applyOptions({ timeScale: { visible: true, timeVisible: true, secondsVisible: true }, crosshair: {
mode: LightweightCharts.CrosshairMode.Normal, labelVisible: true
}})
const candlestickSeries = chart.addCandlestickSeries();
const candlestickSeries = chart.addCandlestickSeries({ lastValueVisible: true, priceLineWidth:2, priceLineColor: "red", priceFormat: { type: 'price', precision: 2, minMove: 0.01 }});
candlestickSeries.priceScale().applyOptions({
scaleMargins: {
top: 0.1, // highest point of the series will be 10% away from the top
bottom: 0.4, // lowest point will be 40% away from the bottom
},
});
const volumeSeries = chart.addHistogramSeries({title: "Volume", color: '#26a69a', priceFormat: {type: 'volume'}, priceScaleId: ''});
volumeSeries.priceScale().applyOptions({
// set the positioning of the volume series
@ -21,11 +23,13 @@ volumeSeries.priceScale().applyOptions({
});
const vwapSeries = chart.addLineSeries({
title: "vwap",
// title: "vwap",
color: '#2962FF',
lineWidth: 1,
lastValueVisible: false
})
chart.timeScale().fitContent();
//TBD dynamicky zobrazovat vsechny indikatory
//document.getElementById('chart').style.display = 'inline-block';
@ -54,7 +58,7 @@ chart.subscribeCrosshairMove((param) => {
firstRow.innerText += item.name + " " + ind.value + " ";
});
firstRow.innerText += 'vwap' + ' ' + vwap.toFixed(2) + " o" + bars.open + " h" + bars.high + " l" + bars.low + " c" + bars.close + " v" + volumes.value;
firstRow.innerText += ' vwap' + ' ' + vwap.toFixed(2) + " O" + bars.open + " H" + bars.high + " L" + bars.low + " C" + bars.close + " V" + volumes.value + "";
}
else {
firstRow.innerText = '-';

View File

@ -1,6 +1,9 @@
const momentumIndicatorNames = ["roc", "slope"]
var indList = []
var pbiList = []
var ws = null;
var positionsPriceLine = null
var limitkaPriceLine = null
function connect(event) {
var runnerId = document.getElementById("runnerId")
try {
@ -16,12 +19,6 @@ function connect(event) {
document.getElementById("chart").style.display = "block"
}
ws.onmessage = function(event) {
//var messages = document.getElementById('messages')
//var message = document.createElement('li')
//var content = document.createTextNode(event.data)
//message.appendChild(content)
//messages.appendChild(message)
var parsed_data = JSON.parse(event.data)
console.log(JSON.stringify(parsed_data))
@ -53,6 +50,107 @@ function connect(event) {
});
}
//loglist
if (parsed_data.hasOwnProperty("iter_log")) {
iterLogList = parsed_data.iter_log
console.log("Incoming logline object")
var lines = document.getElementById('lines')
var line = document.createElement('div')
line.classList.add("line")
const newLine = document.createTextNode("-----------------NEXT ITER------------------")
line.appendChild(newLine)
lines.appendChild(line)
iterLogList.forEach((logLine) => {
console.log("logline item")
console.log(JSON.stringify(logLine,null,2))
row = logLine.time + " <strong>" + logLine.event + "</strong>:" + logLine.message;
str_row = JSON.stringify(logLine.details, null, 2)
var lines = document.getElementById('lines')
var line = document.createElement('div')
line.classList.add("line")
//const newLine = document.createTextNode(row)
line.insertAdjacentHTML( 'beforeend', row );
//line.appendChild(newLine)
var pre = document.createElement("span")
pre.classList.add("pidi")
const stLine = document.createTextNode(str_row)
pre.appendChild(stLine)
line.appendChild(pre)
lines.appendChild(line)
});
$('#messages').animate({
scrollTop: $('#lines')[0].scrollHeight}, 2000);
}
//limitka
if (parsed_data.hasOwnProperty("limitka")) {
limitka = parsed_data.limitka
const limitkaLine = {
price: limitka.price,
color: '#1ed473',
lineWidth: 1,
lineStyle: 1, // LineStyle.Dotted
axisLabelVisible: true,
title: "SELL:XX",
};
if (limitkaPriceLine !== null) {
candlestickSeries.removePriceLine(limitkaPriceLine)
}
limitkaPriceLine = candlestickSeries.createPriceLine(limitkaLine);
}
if (parsed_data.hasOwnProperty("pendingbuys")) {
pendingbuys = parsed_data.pendingbuys
//vymazeme vsechny predchozi instance pendingbuys
if (pbiList.length) {
console.log(pbiList)
pbiList.forEach((line) => {
candlestickSeries.removePriceLine(line)
});
pbiList = []
}
//zobrazime pendingbuys a ulozime instance do pole
console.log("pred loopem")
for (const [orderid, price] of Object.entries(pendingbuys)) {
console.log("v loopu", price)
const pbLine = {
price: parseFloat(price),
color: "#e3a059",
lineWidth: 1,
lineStyle: 1, // LineStyle.Dotted
axisLabelVisible: true,
title: "BUY:",
};
pbLineInstance = candlestickSeries.createPriceLine(pbLine);
pbiList.push(pbLineInstance)
}
}
if (parsed_data.hasOwnProperty("positions")) {
positions = parsed_data.positions
const posLine = {
price: positions.avgp,
color: 'black',
lineWidth: 1,
lineStyle: 1, // LineStyle.Dotted
axisLabelVisible: true,
title: "POS:"+positions.positions,
};
if (positionsPriceLine !== null) {
candlestickSeries.removePriceLine(positionsPriceLine)
}
positionsPriceLine = candlestickSeries.createPriceLine(posLine);
}
if (parsed_data.hasOwnProperty("indicators")) {
var indicators = parsed_data.indicators
//if there are indicators it means there must be at least two keys (except time which is always present)
@ -73,8 +171,9 @@ function connect(event) {
}
else {
obj.series = chart.addLineSeries({
title: key,
//title: key,
lineWidth: 1,
lastValueVisible: false
})
}
obj.series.update({
@ -95,6 +194,7 @@ function connect(event) {
console.log(`${key}: ${value}`);
}
}
//chart.timeScale().fitContent();
}
}
ws.onclose = function(event) {

View File

@ -15,6 +15,7 @@
align-self: auto;
order: 0;
margin-inline-start: 50px;
padding-bottom: 10px;
}
.chartContainer {
@ -30,4 +31,36 @@
font-size: 16px;
line-height: 18px;
font-weight: 300;
}
#msgContainer {
display: grid;
overflow: auto;
height: 568px;
}
.msgContainerInner {
display: flex;
overflow: auto;
height: 568px;
flex-direction: column-reverse;
}
pre {
display: block;
/* padding: 9.5px; */
/* margin: 0 0 10px; */
font-size: 10px;
/* line-height: 2.428571; */
color: #333;
word-break: break-all;
word-wrap: break-word;
/* background-color: #f5f5f5; */
/* border: 1px solid #ccc; */
border-radius: 4px;
}
.pidi {
display: block;
font-size: smaller;
}

View File

@ -17,11 +17,13 @@ class StrategyOrderLimitVykladaci(Strategy):
super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se)
async def orderUpdateBuy(self, data: TradeUpdate):
o: Order = data.order
self.state.ilog(e="NOT:BUY_NOT_INCOMING", status=o.status, orderid=str(o.id))
if o.status == OrderStatus.FILLED or o.status == OrderStatus.CANCELED:
#pokud existuje objednavka v pendingbuys - vyhodime ji
if self.state.vars.pendingbuys.pop(str(o.id), False):
self.state.ilog(e="NOT:BUY_NOT_DELETE_PB", msg="mazeme z pendingu", orderid=str(o.id), pb=self.state.vars.pendingbuys)
print("limit buy filled or cancelled. Vyhazujeme z pendingbuys.")
ic(self.state.vars.pendingbuys)
@ -34,13 +36,20 @@ class StrategyOrderLimitVykladaci(Strategy):
self.state.avgp = float(data.price)
price=price2dec(float(o.filled_avg_price)+self.state.vars.profit)
self.state.vars.limitka = await self.interface.sell_l(price=price, size=o.filled_qty)
self.state.vars.limitka_price = price
self.state.ilog(e="NOT:BUY_NOT_LIMITKA_CREATE", msg="limitka neni vytvarime", orderid=str(o.id), limitka=str(self.state.vars.limitka), limtka_price=self.state.vars.limitka_price)
else:
#avgp, pos
self.state.avgp, self.state.positions = self.state.interface.pos()
cena = price2dec(float(self.state.avgp) + float(self.state.vars.profit))
try:
puvodni = self.state.vars.limitka
self.state.vars.limitka = await self.interface.repl(price=cena,orderid=self.state.vars.limitka,size=int(self.state.positions))
self.state.vars.limitka_price = cena
self.state.ilog(e="NOT:BUY_NOT_LIMITKA_REPLACE", msg="limitka existuje-replace", orderid=str(o.id), limitka=str(self.state.vars.limitka), limtka_price=self.state.vars.limitka_price, puvodni_limitka=str(puvodni))
except APIError as e:
self.state.ilog(e="NOT:BUY_NOT_LIMITKA_REPLACE_ERROR", msg=str(e), orderid=str(o.id), limitka=str(self.state.vars.limitka), limitka_price=self.state.vars.limitka_price, puvodni_limitka=str(puvodni))
#stejne parametry - stava se pri rychle obratce, nevadi
if e.code == 42210000: return 0,0
else:
@ -49,6 +58,7 @@ class StrategyOrderLimitVykladaci(Strategy):
async def orderUpdateSell(self, data: TradeUpdate):
if data.event == TradeEvent.PARTIAL_FILL:
self.state.ilog(e="NOT:SELL_PARTIAL_FILL", msg="pouze update pozic", orderid=str(data.order.id))
ic("partial fill jen udpatujeme pozice")
self.state.avgp, self.state.positions = self.interface.pos()
elif data.event == TradeEvent.FILL or data.event == TradeEvent.CANCELED:
@ -60,9 +70,11 @@ class StrategyOrderLimitVykladaci(Strategy):
self.state.avgp, self.state.positions = self.interface.pos()
ic(self.state.avgp, self.state.positions)
self.state.vars.limitka = None
self.state.vars.limitka_price = None
self.state.vars.lastbuyindex = -5
self.state.vars.jevylozeno = 0
await self.state.cancel_pending_buys()
self.state.ilog(e="NOT:SELL_FILL_OR_CANCEL", msg="mazeme limitku a pb", orderid=str(data.order.id), pb=self.state.vars.pendingbuys)
#this parent method is called by strategy just once before waiting for first data
def strat_init(self):
@ -77,6 +89,7 @@ class StrategyOrderLimitVykladaci(Strategy):
def buy(self, size = None, repeat: bool = False):
print("overriden method to size&check maximum ")
if int(self.state.positions) >= self.state.vars.maxpozic:
self.state.ilog(e="BUY_REQ_MAX_POS_REACHED", msg="Pozadavek na buy, max pozic", curr_positions=self.state.positions)
print("max mnostvi naplneno")
return 0
if size is None:
@ -92,12 +105,13 @@ class StrategyOrderLimitVykladaci(Strategy):
def buy_l(self, price: float = None, size = None, repeat: bool = False):
print("entering overriden BUY")
if int(self.state.positions) >= self.state.vars.maxpozic:
print("max mnostvi naplneno")
self.state.ilog(e="BUY_REQ_MAX_POS_REACHED", msg="Pozadavek na buy, max pozic", price=price, size=size, curr_positions=self.state.positions)
return 0
if size is None: size=self.state.vars.chunk
if price is None: price=price2dec((self.state.interface.get_last_price(self.symbol)))
ic(price)
print("odesilame LIMIT s cenou/qty", price, size)
self.state.ilog(e="BUY_REQ_ORDER_SENDING", msg="Pozadavek na buy, odesilame do if", price=price, size=size)
order = self.state.interface.buy_l(price=price, size=size)
print("ukladame pendingbuys")
self.state.vars.pendingbuys[str(order)]=price
@ -105,9 +119,11 @@ class StrategyOrderLimitVykladaci(Strategy):
self.state.vars.lastbuyindex = self.state.bars['index'][-1]
ic(self.state.blockbuy)
ic(self.state.vars.lastbuyindex)
self.state.ilog(e="BUY_REQ_ORDER_SENT", msg="Uloženo do pb", order=str(order), pb=self.state.vars.pendingbuys)
async def cancel_pending_buys(self):
print("cancel pending buys called.")
self.state.ilog(e="CANCEL_ALL_PB_REQUESTED", pb=self.state.vars.pendingbuys)
##proto v pendingbuys pridano str(), protoze UUIN nejde serializovat
##padalo na variable changed during iteration, pridano
if len(self.state.vars.pendingbuys)>0:
@ -117,7 +133,9 @@ class StrategyOrderLimitVykladaci(Strategy):
#nejprve vyhodime z pendingbuys
self.state.vars.pendingbuys.pop(key, False)
res = self.interface.cancel(key)
self.state.ilog(e="PB_CANCELLED", orderid=key, res=str(res))
print("CANCEL PENDING BUYS RETURN", res)
self.state.vars.pendingbuys={}
self.state.vars.jevylozeno = 0
print("cancel pending buys end")
self.state.ilog(e="CANCEL_ALL_PB_FINISHED", pb=self.state.vars.pendingbuys)

View File

@ -251,6 +251,7 @@ class Strategy:
elif self.pe.is_set():
print(current_thread().name, "Paused.")
continue
#self.state.iter_log(event="INGEST",msg="New data ingested", item=item)
print("New data ingested")
#calling main loop
self.strat_loop(item=item)
@ -339,7 +340,25 @@ class Strategy:
rt_out["indicators"][key]= value[-1]
except IndexError:
pass
print(rt_out)
#vkladame average price and positions, pokud existuji
#self.state.avgp , self.state.positions
rt_out["positions"] = dict(time=self.state.time, positions=self.state.positions, avgp=self.state.avgp)
#vkladame limitku a pendingbuys
try:
rt_out["pendingbuys"] = self.state.vars.pendingbuys
rt_out["limitka"] = dict(id=self.state.vars.limitka, price=self.state.vars.limitka_price)
except Exception as e:
print(str(e))
pass
#vkladame iteration log (do toho si muze instance vlozit cokoliv relavantniho pro danou iteraci) a po iteraci se smaze
if len(self.state.iter_log_list) > 0:
rt_out["iter_log"] = self.state.iter_log_list
#print(rt_out)
print("RTQUEUE INSERT")
#send current values to Realtime display on frontend
@ -347,6 +366,10 @@ class Strategy:
self.rtqueue.put(json.dumps(rt_out, default=json_serial))
print("RTQUEUE", self.rtqueue)
#cleaning iterlog lsit
#TODO pridat cistku i mimo RT blok
self.state.iter_log_list = []
# inicializace poplatna typu strategie (např. u LIMITu dotažení existující limitky)
def strat_init(self):
@ -448,4 +471,12 @@ class StrategyState:
self.buy_l = self.interface.buy_l
self.sell = self.interface.sell
self.sell_l = self.interface.sell_l
self.cancel_pending_buys = None
self.cancel_pending_buys = None
self.iter_log_list = []
def ilog(self, e: str = None, msg: str = None, **kwargs):
if e is None:
row = dict(time=self.time, message=msg, details=kwargs)
else:
row = dict(time=self.time, event=e, message=msg, details=kwargs)
self.iter_log_list.append(row)