bugfixes a pridana moznost z archivu mit json

This commit is contained in:
David Brazda
2023-05-11 17:30:41 +02:00
parent 8be0fb8a3a
commit 6e775a33d9
21 changed files with 1223 additions and 39 deletions

View File

@ -0,0 +1,487 @@
import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.strategy.base import StrategyState
from v2realbot.strategy.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
from v2realbot.indicators.indicators import ema
from v2realbot.indicators.oscillators import rsi, stochastic_oscillator, stochastic_rsi, absolute_price_oscillator, percentage_price_oscillator
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get
from datetime import datetime
#from icecream import install, ic
#from rich import print
from threading import Event
from msgpack import packb, unpackb
import asyncio
import os
from traceback import format_exc
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
#ic(state.avgp, state.positions)
#ic(state.vars)
#ic(data)
#
def is_defensive_mode():
akt_pozic = int(state.positions)
max_pozic = int(state.vars.maxpozic)
def_mode_from = safe_get(state.vars, "def_mode_from")
if def_mode_from == None: def_mode_from = max_pozic/2
if akt_pozic >= int(def_mode_from):
state.ilog(e=f"DEFENSIVE mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions)
return True
else:
state.ilog(e=f"STANDARD mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions)
return False
def get_limitka_price():
def_profit = safe_get(state.vars, "def_profit")
if def_profit == None: def_profit = state.vars.profit
if is_defensive_mode():
return price2dec(float(state.avgp)+float(def_profit))
else:
return price2dec(float(state.avgp)+float(state.vars.profit))
def consolidation():
##CONSOLIDATION PART - moved here, musí být před nákupem, jinak to dělalo nepořádek v pendingbuys
#docasne zkusime konzolidovat i kdyz neni vylozeno (aby se srovnala limitka ve vsech situacich)
if state.vars.jevylozeno == 1 or 1==1:
##CONSOLIDATION PART kazdy Nty bar dle nastaveni
if int(data["index"])%int(state.vars.consolidation_bar_count) == 0:
print("***CONSOLIDATION ENTRY***")
state.ilog(e="CONSOLIDATION ENTRY ***")
orderlist = state.interface.get_open_orders(symbol=state.symbol, side=None)
#pro jistotu jeste dotahneme aktualni pozice
state.avgp, state.positions = state.interface.pos()
#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
limitka_qty = 0
limitka_filled_qty = 0
for o in orderlist:
if o.side == OrderSide.SELL:
if limitka_found:
state.ilog(e="nalezeno vicero sell objednavek, bereme prvni, ostatni - rusime")
result=state.interface.cancel(o.id)
state.ilog(e="zrusena objednavka"+str(o.id), message=result)
continue
#print("Nalezena LIMITKA")
limitka_found = True
state.vars.limitka = o.id
state.vars.limitka_price = o.limit_price
limitka_qty = int(o.qty)
limitka_filled_qty = int(o.filled_qty)
#aktualni mnozstvi = puvodni minus filled
if limitka_filled_qty is not None:
print("prepocitavam filledmnozstvi od limitka_qty a filled_qty", limitka_qty, limitka_filled_qty)
limitka_qty = int(limitka_qty) - int(limitka_filled_qty)
##TODO sem pridat upravu ceny
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
pendingbuys_new[str(o.id)]=float(o.limit_price)
state.ilog(e="Konzolidace limitky", msg=f"stejna:{(str(limitka_old)==str(state.vars.limitka))}", limitka_old=str(limitka_old), limitka_new=str(state.vars.limitka), limitka_new_price=state.vars.limitka_price, limitka_qty=limitka_qty, limitka_filled_qty=limitka_filled_qty)
#pokud mame
#neni limitka, ale mela by byt - vytváříme ji
if int(state.positions) > 0 and state.vars.limitka is None:
state.ilog(e="Limitka neni, ale mela by být.", msg=f"{state.positions=}")
price=get_limitka_price()
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions)))
state.vars.limitka_price = price
if state.vars.limitka == -1:
state.ilog(e="Vytvoreni limitky neprobehlo, vracime None", msg=f"{state.vars.limitka=}")
state.vars.limitka = None
state.vars.limitka_price = None
else:
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions)
#existuje a nesedi mnozstvi nebo cena
elif state.vars.limitka is not None and int(state.positions) > 0 and ((int(state.positions) != int(limitka_qty)) or float(state.vars.limitka_price) != float(get_limitka_price())):
#limitka existuje, ale spatne mnostvi - updatujeme
state.ilog(e=f"Limitka existuje, ale spatne mnozstvi nebo CENA - updatujeme", msg=f"{state.positions=} {limitka_qty=} {state.vars.limitka_price=}", nastavenacena=state.vars.limitka_price, spravna_cena=get_limitka_price(), pos=state.positions, limitka_qty=limitka_qty)
#snad to nespadne, kdyztak pridat exception handling
puvodni = state.vars.limitka
#TBD zde odchytit nejak result
state.vars.limitka = asyncio.run(state.interface.repl(price=get_limitka_price(), orderid=state.vars.limitka, size=int(state.positions)))
if state.vars.limitka == -1:
state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni)
state.vars.limitka = puvodni
else:
limitka_qty = int(state.positions)
state.ilog(e="Změněna limitka", limitka=str(state.vars.limitka), limitka_price=state.vars.limitka_price, limitka_qty=limitka_qty)
#tbd pokud se bude vyskytovat pak pridat ještě konzolidaci ceny limitky
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 jevylozeno", msg=state.vars.jevylozeno)
#print(limitka)
#print(pendingbuys_new)
#print(pendingbuys)
#print(len(pendingbuys))
#print(len(pendingbuys_new))
#print(jevylozeno)
print("***CONSOLIDATION EXIT***")
state.ilog(e="CONSOLIDATION EXIT ***")
else:
state.ilog(e="No time for consolidation", msg=data["index"])
print("no time for consolidation", data["index"])
#mozna presunout o level vys
def vyloz():
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci
#curve = [0.01, 0.01, 0, 0, 0.01, 0, 0, 0, 0.02, 0, 0, 0, 0.03, 0,0,0,0,0, 0.02, 0,0,0,0,0,0, 0.02]
curve = state.vars.curve
##defenzivni krivka pro
curve_def = state.vars.curve_def
#vykladani po 5ti kusech, když zbývají 2 a méně, tak děláme nový výklad
vykladka = state.vars.vykladka
#kolik muzu max vylozit
kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk))
akt_pozic = int(state.positions)
max_pozic = int(state.vars.maxpozic)
#mame polovinu a vic vylozeno, pouzivame defenzicni krivku
if is_defensive_mode():
state.ilog(e="DEF: Pouzivame defenzivni krivku", akt_pozic=akt_pozic, max_pozic=max_pozic, curve_def=curve_def)
curve = curve_def
#zaroven docasne menime ticks2reset na defenzivni 0.06
state.vars.ticks2reset = 0.06
state.ilog(e="DEF: Menime tick2reset na 0.06", ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup)
else:
#vracime zpet, pokud bylo zmeneno
if state.vars.ticks2reset != state.vars.ticks2reset_backup:
state.vars.ticks2reset = state.vars.ticks2reset_backup
state.ilog(e="DEF: Menime tick2reset zpet na"+str(state.vars.ticks2reset), ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup)
if kolikmuzu < vykladka: vykladka = kolikmuzu
if len(curve) < vykladka:
vykladka = len(curve)
qty = int(state.vars.chunk)
last_price = price2dec(state.interface.get_last_price(state.symbol))
#profit = float(state.vars.profit)
price = last_price
state.ilog(e="BUY Vykladame", msg=f"first price {price=} {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
##VAR - na zaklade conf. muzeme jako prvni posilat MARKET order
if safe_get(state.vars, "first_buy_market") == True:
#pri defenzivnim rezimu pouzivame vzdy LIMIT order
if is_defensive_mode():
state.ilog(e="DEF mode on, odesilame jako prvni limitku")
state.buy_l(price=price, size=qty)
else:
state.ilog(e="Posilame jako prvni MARKET order")
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)
for i in range(0,vykladka-1):
price = price2dec(float(price - curve[i]))
if price == last_price:
qty = qty + int(state.vars.chunk)
else:
state.buy_l(price=price, size=qty)
#print(i,"BUY limitka - delta",curve[i]," cena:", price, "mnozstvi:", qty)
qty = int(state.vars.chunk)
last_price = price
state.vars.blockbuy = 1
state.vars.jevylozeno = 1
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.vars.blockbuy == 1 and state.rectype == RecordType.CBAR:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.vars.blockbuy = 0
return 0
state.ilog(e="-----")
#EMA INDICATOR -
#plnime MAcko - nyni posilame jen N poslednich hodnot
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
try:
ma = int(state.vars.MA)
#poslednich ma hodnot
source = state.bars.close[-ma:] #state.bars.vwap
ema_value = ema(source, ma)
state.indicators.ema.append(trunc(ema_value[-1],3))
except Exception as e:
state.ilog(e="EMA ukladame 0", message=str(e)+format_exc())
state.indicators.ema.append(0)
#EMA SLOW
try:
ma = 100
#poslednich ma hodnot
source = state.bars.hlcc4[-ma:] #state.bars.vwap
emaSlow_value = ema(source, ma)
emaSlow = trunc(emaSlow_value[-1],3)
state.indicators.emaSlow.append(emaSlow)
state.ilog(e=f"emaSlow {emaSlow=}", emaSlow=state.indicators.emaSlow[-5:])
except Exception as e:
state.ilog(e=f"emaSlow {ma=} ukladame 0", message=str(e)+format_exc())
state.indicators.emaSlow.append(0)
#EMA FAST
try:
ma = 20
#poslednich ma hodnot
source = state.bars.hlcc4[-ma:] #state.bars.vwap
emaFast_value = ema(source, ma)
emaFast = trunc(emaFast_value[-1],3)
state.indicators.emaFast.append(emaFast)
state.ilog(e=f"emaFast {emaFast=}", emaFast=state.indicators.emaFast[-5:])
except Exception as e:
state.ilog(e=f"emaFast {ma=} ukladame 0", message=str(e)+format_exc())
state.indicators.emaFast.append(0)
#RSI14
try:
rsi_length = 14
#poslednich ma hodnot
source = state.bars.close #[-rsi_length:] #state.bars.vwap
rsi_res = rsi(source, rsi_length)
rsi_value = trunc(rsi_res[-1],3)
state.indicators.RSI14.append(rsi_value)
state.ilog(e=f"RSI {rsi_length=} {rsi_value=}", rsi_indicator=state.indicators.RSI14[-5:])
except Exception as e:
state.ilog(e=f"RSI {rsi_length=} ukladame 0", message=str(e)+format_exc())
state.indicators.RSI14.append(0)
#stoch
try:
stoch_length = 14
#poslednich ma hodnot
source_high = state.bars.high #[-rsi_length:] #state.bars.vwap
source_low = state.bars.low
source_close=state.bars.close
stoch_res1, stoch_res2 = stochastic_oscillator(source_high, source_low, source_close)
stoch_value1 = trunc(stoch_res1[-1],3)
stoch_value2 = trunc(stoch_res2[-1],3)
state.indicators.stoch1.append(stoch_value1)
state.indicators.stoch2.append(stoch_value2)
state.ilog(e=f"stoch {stoch_value1=} {stoch_value2=}", stoch1=state.indicators.stoch1[-5:], stoch2=state.indicators.stoch2[-5:])
except Exception as e:
state.ilog(e=f"stoch ukladame 0", message=str(e)+format_exc())
state.indicators.stoch1.append(0)
state.indicators.stoch2.append(0)
#absolute price oscillator
#meri mezeru mezi dvemi MACky (ato bud absolut price nebo percentage)
try:
short = 1
long = 20
#poslednich ma hodnot
source = state.bars.close #[-rsi_length:] #state.bars.vwap
apo_res = absolute_price_oscillator(source, short,long)
apo_value = trunc(apo_res[-1],3)
state.indicators.apo.append(apo_value)
state.ilog(e=f"apo {apo_value=}", apo_indicator=state.indicators.apo[-5:])
except Exception as e:
state.ilog(e=f"apo ukladame 0", message=str(e)+format_exc())
state.indicators.apo.append(0)
#percentage price oscillator
try:
short = 1
long = 20
#poslednich ma hodnot
source = state.bars.close #[-rsi_length:] #state.bars.vwap
ppo_res = percentage_price_oscillator(source, short,long)
ppo_value = trunc(ppo_res[-1],3)
state.indicators.ppo.append(ppo_value)
state.ilog(e=f"poo {ppo_value=}", ppo_indicator=state.indicators.ppo[-5:])
except Exception as e:
state.ilog(e=f"ppo ukladame 0", message=str(e)+format_exc())
state.indicators.ppo.append(0)
#SLOPE INDICATOR
#úhel stoupání a klesání vyjádřený mezi -1 až 1
#pravý bod přímky je aktuální cena, levý je průměr X(lookback offset) starších hodnot od slope_lookback.
#obsahuje statický indikátor (angle) pro vizualizaci
try:
slope = 99
slope_lookback = int(state.vars.slope_lookback)
minimum_slope = float(state.vars.minimum_slope)
lookback_offset = int(state.vars.lookback_offset)
if len(state.bars.close) > (slope_lookback + lookback_offset):
array_od = slope_lookback + lookback_offset
array_do = slope_lookback
lookbackprice_array = state.bars.vwap[-array_od:-array_do]
#obycejný prumer hodnot
lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
#výpočet úhlu
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
slope = round(slope, 4)
state.indicators.slope.append(slope)
#angle je ze slope
state.statinds.angle = dict(time=state.bars.time[-1], price=state.bars.close[-1], lookbacktime=state.bars.time[-slope_lookback], lookbackprice=lookbackprice, minimum_slope=minimum_slope)
#slope MA vyrovna vykyvy ve slope, dále pracujeme se slopeMA
slope_MA_length = 5
source = state.indicators.slope[-slope_MA_length:]
slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap
slopeMA = slopeMAseries[-1]
state.indicators.slopeMA.append(slopeMA)
state.ilog(e=f"{slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-10:])
#dale pracujeme s timto MAckovanym slope
slope = slopeMA
else:
#pokud plnime historii musime ji plnit od zacatku, vsehcny idenitifkatory maji spolecny time
#kvuli spravnemu zobrazovani na gui
state.indicators.slope.append(0)
state.indicators.slopeMA.append(0)
state.ilog(e="Slope - not enough data", slope_lookback=slope_lookback, slope=state.indicators.slope, slopeMA=state.indicators.slopeMA)
except Exception as e:
print("Exception in NEXT Slope Indicator section", str(e))
state.ilog(e="EXCEPTION", msg="Exception in Slope Indicator section" + str(e) + format_exc())
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
consolidation()
#HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru
lp = state.interface.get_last_price(symbol=state.symbol)
state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", last_price=lp, data=data, stratvars=state.vars)
#SLOPE ANGLE PROTECTIONs
#slope zachycuje rychle sestupy, pripadne zrusi nakupni objednavky
if slope < minimum_slope: # or slopeMA<maxSlopeMA:
print("OCHRANA SLOPE TOO HIGH")
# if slopeMA<maxSlopeMA:
# state.ilog(e="Slope MA too high "+str(slopeMA)+" max:"+str(maxSlopeMA))
state.ilog(e=f"Slope too high {slope}")
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, res=res)
print("slope", slope)
print("min slope", minimum_slope)
if state.vars.jevylozeno == 0:
print("Neni vylozeno, muzeme testovat nakup")
#pokud je defenziva, buy triggeruje defenzivni def_trend
#TBD
if isfalling(state.indicators.ema,state.vars.Trend) and slope > minimum_slope:
vyloz()
if state.vars.jevylozeno == 1:
#pokud mame vylozeno a cena je vetsi nez tick2reset
if len(state.vars.pendingbuys)>0:
maxprice = max(state.vars.pendingbuys.values())
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + float(state.vars.ticks2reset):
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys)
#PENDING BUYS SPENT - PART
#pokud mame vylozeno a pendingbuys se vyklepou a
# 1 vykladame idned znovu
# vyloz()
# 2 nebo - počkat zase na signál a pokračovat dál
# state.vars.blockbuy = 0
# state.vars.jevylozeno = 0
# 3 nebo - počkat na signál s enablovaným lastbuy indexem (tzn. počká nutně ještě pár barů)
#podle BT vyhodnejsi vylozit ihned
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 ??
#kdykoliv se muze notifikace ztratit
# - pendingbuys - vsechny open orders buy
# - limitka - open order sell
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
# if int(state.oe.poz)>0 and state.oe.limitka == 0:
# #pro jistotu updatujeme pozice
# state.oe.avgp, state.oe.poz = state.oe.pos()
# if int(state.oe.poz) > 0:
# cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
# print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
# print("aktuzalni ltp",ltp.price[state.oe.symbol])
# try:
# state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
# print("vytvorena limitka", state.oe.limitka)
# except Exception as e:
# print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
# pass
# ##raise Exception(e)
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.indicators['ema'] = []
state.indicators['slope'] = []
state.indicators['slopeMA'] = []
state.indicators['emaSlow'] = []
state.indicators['emaFast'] = []
state.indicators['RSI14'] = []
state.indicators['stoch1'] = []
state.indicators['stoch2'] = []
state.indicators['apo'] = []
state.indicators['ppo'] = []
#static indicators - those not series based
state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"])
state.vars["ticks2reset_backup"] = state.vars.ticks2reset

View File

@ -0,0 +1,521 @@
import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.strategy.base import StrategyState
from v2realbot.strategy.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
from v2realbot.indicators.indicators import ema
from v2realbot.indicators.oscillators import rsi
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get
from datetime import datetime
#from icecream import install, ic
#from rich import print
from threading import Event
from msgpack import packb, unpackb
import asyncio
import os
from traceback import format_exc
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
""""
Kope Vykladaci strategie s navic pridanym RSI
- pokud RSI > 50
- rusime pendingbuye
- netriggerujeme buy
"""
stratvars = AttributeDict(maxpozic = 400,
def_mode_from = 200,
chunk = 10,
MA = 2,
Trend = 2,
profit = 0.02,
def_profit = 0.01,
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],
curve_def = [0.02, 0.02, 0.02, 0, 0, 0.02, 0, 0, 0, 0.02],
blockbuy = 0,
ticks2reset = 0.04,
consolidation_bar_count = 10,
slope_lookback = 300,
lookback_offset = 20,
minimum_slope = -0.05,
first_buy_market = False
)
##toto rozparsovat a strategii spustit stejne jako v main
toml_string = """
[[strategies]]
name = "V1 na BAC"
symbol = "BAC"
script = "ENTRY_backtest_strategyVykladaci"
class = "StrategyOrderLimitVykladaci"
open_rush = 0
close_rush = 0
[strategies.stratvars]
maxpozic = 200
chunk = 10
MA = 6
Trend = 5
profit = 0.02
lastbuyindex=-6
pendingbuys={}
limitka = "None"
jevylozeno=0
vykladka=5
curve = [0.01, 0.01, 0.01,0.01, 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]
blockbuy = 0
ticks2reset = 0.04
[[strategies.add_data]]
symbol="BAC"
rectype="bar"
timeframe=5
update_ltp=true
align="round"
mintick=0
minsize=100
exthours=false
"""
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
#ic(state.avgp, state.positions)
#ic(state.vars)
#ic(data)
#
def is_defensive_mode():
akt_pozic = int(state.positions)
max_pozic = int(state.vars.maxpozic)
def_mode_from = safe_get(state.vars, "def_mode_from")
if def_mode_from == None: def_mode_from = max_pozic/2
if akt_pozic >= int(def_mode_from):
state.ilog(e=f"DEFENSIVE mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions)
return True
else:
state.ilog(e=f"STANDARD mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions)
return False
def get_limitka_price():
def_profit = safe_get(state.vars, "def_profit")
if def_profit == None: def_profit = state.vars.profit
if is_defensive_mode():
return price2dec(float(state.avgp)+float(def_profit))
else:
return price2dec(float(state.avgp)+float(state.vars.profit))
def consolidation():
##CONSOLIDATION PART - moved here, musí být před nákupem, jinak to dělalo nepořádek v pendingbuys
#docasne zkusime konzolidovat i kdyz neni vylozeno (aby se srovnala limitka ve vsech situacich)
if state.vars.jevylozeno == 1 or 1==1:
##CONSOLIDATION PART kazdy Nty bar dle nastaveni
if int(data["index"])%int(state.vars.consolidation_bar_count) == 0:
print("***CONSOLIDATION ENTRY***")
state.ilog(e="CONSOLIDATION ENTRY ***")
orderlist = state.interface.get_open_orders(symbol=state.symbol, side=None)
#pro jistotu jeste dotahneme aktualni pozice
state.avgp, state.positions = state.interface.pos()
#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
limitka_qty = 0
limitka_filled_qty = 0
for o in orderlist:
if o.side == OrderSide.SELL:
if limitka_found:
state.ilog(e="nalezeno vicero sell objednavek, bereme prvni, ostatni - rusime")
result=state.interface.cancel(o.id)
state.ilog(e="zrusena objednavka"+str(o.id), message=result)
continue
#print("Nalezena LIMITKA")
limitka_found = True
state.vars.limitka = o.id
state.vars.limitka_price = o.limit_price
limitka_qty = int(o.qty)
limitka_filled_qty = int(o.filled_qty)
#aktualni mnozstvi = puvodni minus filled
if limitka_filled_qty is not None:
print("prepocitavam filledmnozstvi od limitka_qty a filled_qty", limitka_qty, limitka_filled_qty)
limitka_qty = int(limitka_qty) - int(limitka_filled_qty)
##TODO sem pridat upravu ceny
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
pendingbuys_new[str(o.id)]=float(o.limit_price)
state.ilog(e="Konzolidace limitky", msg=f"stejna:{(str(limitka_old)==str(state.vars.limitka))}", limitka_old=str(limitka_old), limitka_new=str(state.vars.limitka), limitka_new_price=state.vars.limitka_price, limitka_qty=limitka_qty, limitka_filled_qty=limitka_filled_qty)
#pokud mame
#neni limitka, ale mela by byt - vytváříme ji
if int(state.positions) > 0 and state.vars.limitka is None:
state.ilog(e="Limitka neni, ale mela by být.", msg=f"{state.positions=}")
price=get_limitka_price()
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions)))
state.vars.limitka_price = price
if state.vars.limitka == -1:
state.ilog(e="Vytvoreni limitky neprobehlo, vracime None", msg=f"{state.vars.limitka=}")
state.vars.limitka = None
state.vars.limitka_price = None
else:
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions)
#existuje a nesedi mnozstvi nebo cena
elif state.vars.limitka is not None and int(state.positions) > 0 and ((int(state.positions) != int(limitka_qty)) or float(state.vars.limitka_price) != float(get_limitka_price())):
#limitka existuje, ale spatne mnostvi - updatujeme
state.ilog(e=f"Limitka existuje, ale spatne mnozstvi nebo CENA - updatujeme", msg=f"{state.positions=} {limitka_qty=} {state.vars.limitka_price=}", nastavenacena=state.vars.limitka_price, spravna_cena=get_limitka_price(), pos=state.positions, limitka_qty=limitka_qty)
#snad to nespadne, kdyztak pridat exception handling
puvodni = state.vars.limitka
#TBD zde odchytit nejak result
state.vars.limitka = asyncio.run(state.interface.repl(price=get_limitka_price(), orderid=state.vars.limitka, size=int(state.positions)))
if state.vars.limitka == -1:
state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni)
state.vars.limitka = puvodni
else:
limitka_qty = int(state.positions)
state.ilog(e="Změněna limitka", limitka=str(state.vars.limitka), limitka_price=state.vars.limitka_price, limitka_qty=limitka_qty)
#tbd pokud se bude vyskytovat pak pridat ještě konzolidaci ceny limitky
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 jevylozeno", msg=state.vars.jevylozeno)
#print(limitka)
#print(pendingbuys_new)
#print(pendingbuys)
#print(len(pendingbuys))
#print(len(pendingbuys_new))
#print(jevylozeno)
print("***CONSOLIDATION EXIT***")
state.ilog(e="CONSOLIDATION EXIT ***")
else:
state.ilog(e="No time for consolidation", msg=data["index"])
print("no time for consolidation", data["index"])
#mozna presunout o level vys
def vyloz():
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci
#curve = [0.01, 0.01, 0, 0, 0.01, 0, 0, 0, 0.02, 0, 0, 0, 0.03, 0,0,0,0,0, 0.02, 0,0,0,0,0,0, 0.02]
curve = state.vars.curve
##defenzivni krivka pro
curve_def = state.vars.curve_def
#vykladani po 5ti kusech, když zbývají 2 a méně, tak děláme nový výklad
vykladka = state.vars.vykladka
#kolik muzu max vylozit
kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk))
akt_pozic = int(state.positions)
max_pozic = int(state.vars.maxpozic)
#mame polovinu a vic vylozeno, pouzivame defenzicni krivku
if is_defensive_mode():
state.ilog(e="DEF: Pouzivame defenzivni krivku", akt_pozic=akt_pozic, max_pozic=max_pozic, curve_def=curve_def)
curve = curve_def
#zaroven docasne menime ticks2reset na defenzivni 0.06
state.vars.ticks2reset = 0.06
state.ilog(e="DEF: Menime tick2reset na 0.06", ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup)
else:
#vracime zpet, pokud bylo zmeneno
if state.vars.ticks2reset != state.vars.ticks2reset_backup:
state.vars.ticks2reset = state.vars.ticks2reset_backup
state.ilog(e="DEF: Menime tick2reset zpet na"+str(state.vars.ticks2reset), ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup)
if kolikmuzu < vykladka: vykladka = kolikmuzu
if len(curve) < vykladka:
vykladka = len(curve)
qty = int(state.vars.chunk)
last_price = price2dec(state.interface.get_last_price(state.symbol))
#profit = float(state.vars.profit)
price = last_price
state.ilog(e="BUY Vykladame", msg=f"first price {price=} {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
##VAR - na zaklade conf. muzeme jako prvni posilat MARKET order
if safe_get(state.vars, "first_buy_market") == True:
#pri defenzivnim rezimu pouzivame vzdy LIMIT order
if is_defensive_mode():
state.ilog(e="DEF mode on, odesilame jako prvni limitku")
state.buy_l(price=price, size=qty)
else:
state.ilog(e="Posilame jako prvni MARKET order")
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)
for i in range(0,vykladka-1):
price = price2dec(float(price - curve[i]))
if price == last_price:
qty = qty + int(state.vars.chunk)
else:
state.buy_l(price=price, size=qty)
#print(i,"BUY limitka - delta",curve[i]," cena:", price, "mnozstvi:", qty)
qty = int(state.vars.chunk)
last_price = price
state.vars.blockbuy = 1
state.vars.jevylozeno = 1
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.vars.blockbuy == 1 and state.rectype == RecordType.CBAR:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.vars.blockbuy = 0
return 0
state.ilog(e="-----")
#EMA INDICATOR -
#plnime MAcko - nyni posilame jen N poslednich hodnot
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
try:
ma = int(state.vars.MA)
#poslednich ma hodnot
source = state.bars.close[-ma:] #state.bars.vwap
ema_value = ema(source, ma)
state.indicators.ema.append(trunc(ema_value[-1],3))
except Exception as e:
state.ilog(e="EMA ukladame 0", message=str(e)+format_exc())
state.indicators.ema.append(0)
#RSI14 INDICATOR
try:
##mame v atributech nastaveni?
rsi_dont_buy_above = safe_get(state.vars, "rsi_dont_buy_above")
if rsi_dont_buy_above == None:
rsi_dont_buy_above = 50
rsi_buy_signal = False
rsi_dont_buy = False
rsi_length = 14
source = state.bars.close #[-rsi_length:] #state.bars.vwap
rsi_res = rsi(source, rsi_length)
rsi_value = trunc(rsi_res[-1],3)
state.indicators.RSI14.append(rsi_value)
rsi_dont_buy = rsi_value > rsi_dont_buy_above
rsi_buy_signal = rsi_value < 40
state.ilog(e=f"RSI {rsi_length=} {rsi_value=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.indicators.RSI14[-5:])
except Exception as e:
state.ilog(e=f"RSI {rsi_length=} ukladame 0", message=str(e)+format_exc())
state.indicators.RSI14.append(0)
#SLOPE INDICATOR
#úhel stoupání a klesání vyjádřený mezi -1 až 1
#pravý bod přímky je aktuální cena, levý je průměr X(lookback offset) starších hodnot od slope_lookback.
#obsahuje statický indikátor (angle) pro vizualizaci
try:
slope = 99
slope_lookback = int(state.vars.slope_lookback)
minimum_slope = float(state.vars.minimum_slope)
lookback_offset = int(state.vars.lookback_offset)
if len(state.bars.close) > (slope_lookback + lookback_offset):
array_od = slope_lookback + lookback_offset
array_do = slope_lookback
lookbackprice_array = state.bars.vwap[-array_od:-array_do]
#obycejný prumer hodnot
lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
#výpočet úhlu
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
slope = round(slope, 4)
state.indicators.slope.append(slope)
#angle je ze slope
state.statinds.angle = dict(time=state.bars.time[-1], price=state.bars.close[-1], lookbacktime=state.bars.time[-slope_lookback], lookbackprice=lookbackprice, minimum_slope=minimum_slope)
#slope MA vyrovna vykyvy ve slope, dále pracujeme se slopeMA
slope_MA_length = 5
source = state.indicators.slope[-slope_MA_length:]
slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap
slopeMA = slopeMAseries[-1]
state.indicators.slopeMA.append(slopeMA)
state.ilog(e=f"{slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-10:], last_slopesMA=state.indicators.slopeMA[-10:])
#dale pracujeme s timto MAckovanym slope
slope = slopeMA
else:
#pokud plnime historii musime ji plnit od zacatku, vsehcny idenitifkatory maji spolecny time
#kvuli spravnemu zobrazovani na gui
state.indicators.slope.append(0)
state.indicators.slopeMA.append(0)
state.ilog(e="Slope - not enough data", slope_lookback=slope_lookback, slope=state.indicators.slope, slopeMA=state.indicators.slopeMA)
except Exception as e:
print("Exception in NEXT Slope Indicator section", str(e))
state.ilog(e="EXCEPTION", msg="Exception in Slope Indicator section" + str(e) + format_exc())
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
consolidation()
#HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru
#TODO sem pridat aktualni hodnoty vsech indikatoru
lp = state.interface.get_last_price(symbol=state.symbol)
state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", last_price=lp, data=data, stratvars=state.vars)
#SLOPE ANGLE PROTECTIONs
#slope zachycuje rychle sestupy, pripadne zrusi nakupni objednavky
if slope < minimum_slope or rsi_dont_buy: # or slopeMA<maxSlopeMA:
print("OCHRANA SLOPE or RSI TOO HIGH")
# if slopeMA<maxSlopeMA:
# state.ilog(e="Slope MA too high "+str(slopeMA)+" max:"+str(maxSlopeMA))
state.ilog(e=f"Slope or RSI too high {slope=} {rsi_value=}")
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, res=res)
print("slope", slope)
print("min slope", minimum_slope)
if state.vars.jevylozeno == 0:
print("Neni vylozeno, muzeme testovat nakup")
#pokud je defenziva, buy triggeruje defenzivni def_trend
#TBD
#NOVY BUY SIGNAL z RSI < 35
#buy_signal = isfalling(state.indicators.ema,state.vars.Trend)
buy_signal = rsi_buy_signal
if buy_signal and slope > minimum_slope and not rsi_dont_buy:
vyloz()
## testuje aktualni cenu od nejvyssi visici limitky
##toto spoustet jednou za X iterací - ted to jede pokazdé
#pokud to ujede o vic, rusime limitky
#TODO: zvazit jestli nechat i pri otevrenych pozicich, zatim nechavame
#TODO int(int(state.oa.poz)/int(state.variables.chunk)) > X
#TODO predelat mechanismus ticků (zrelativizovat), aby byl pouzitelny na tituly s ruznou cenou
#TODO spoustet 1x za X iteraci nebo cas
if state.vars.jevylozeno == 1:
#pokud mame vylozeno a cena je vetsi nez tick2reset
if len(state.vars.pendingbuys)>0:
maxprice = max(state.vars.pendingbuys.values())
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + float(state.vars.ticks2reset):
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys)
#PENDING BUYS SPENT - PART
#pokud mame vylozeno a pendingbuys se vyklepou a
# 1 vykladame idned znovu
# vyloz()
# 2 nebo - počkat zase na signál a pokračovat dál
# state.vars.blockbuy = 0
# state.vars.jevylozeno = 0
# 3 nebo - počkat na signál s enablovaným lastbuy indexem (tzn. počká nutně ještě pár barů)
#podle BT vyhodnejsi vylozit ihned
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 ??
#kdykoliv se muze notifikace ztratit
# - pendingbuys - vsechny open orders buy
# - limitka - open order sell
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
# if int(state.oe.poz)>0 and state.oe.limitka == 0:
# #pro jistotu updatujeme pozice
# state.oe.avgp, state.oe.poz = state.oe.pos()
# if int(state.oe.poz) > 0:
# cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
# print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
# print("aktuzalni ltp",ltp.price[state.oe.symbol])
# try:
# state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
# print("vytvorena limitka", state.oe.limitka)
# except Exception as e:
# print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
# pass
# ##raise Exception(e)
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.indicators['ema'] = []
state.indicators['slope'] = []
state.indicators['slopeMA'] = []
state.indicators['RSI14'] = []
#static indicators - those not series based
state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"])
state.vars["ticks2reset_backup"] = state.vars.ticks2reset
def main():
# try:
# strat_settings = tomli.loads("]] this is invalid TOML [[")
# except tomli.TOMLDecodeError:
# print("Yep, definitely not valid.")
#strat_settings = dict_replace_value(strat_settings, "None", None)
name = os.path.basename(__file__)
se = Event()
pe = Event()
s = StrategyOrderLimitVykladaci(name = name, symbol = "BAC", account=Account.ACCOUNT1, next=next, init=init, stratvars=stratvars, open_rush=10, close_rush=0, pe=pe, se=se, ilog_save=True)
s.set_mode(mode = Mode.BT,
debug = False,
start = datetime(2023, 4, 14, 10, 42, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 4, 14, 14, 35, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=2,minsize=100,update_ltp=True,align=StartBarAlign.ROUND,mintick=0, exthours=False)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
print("zastavujeme")
if __name__ == "__main__":
main()

View File

@ -572,7 +572,7 @@ class Backtester:
print("BT:get open orders entry") print("BT:get open orders entry")
if len(self.open_orders) == 0: if len(self.open_orders) == 0:
print("BTC: order doesnt exist") print("BTC: order doesnt exist")
return 0 return []
res = [] res = []
#with lock: #with lock:
for o in self.open_orders: for o in self.open_orders:

View File

@ -58,6 +58,7 @@ class RunRequest(BaseModel):
mode: Mode mode: Mode
note: Optional[str] = None note: Optional[str] = None
debug: bool = False debug: bool = False
strat_json: Optional[str] = None
ilog_save: bool = False ilog_save: bool = False
bt_from: datetime = None bt_from: datetime = None
bt_to: datetime = None bt_to: datetime = None
@ -96,6 +97,7 @@ class Runner(BaseModel):
run_profit: Optional[float] run_profit: Optional[float]
run_positions: Optional[int] run_positions: Optional[int]
run_avgp: Optional[float] run_avgp: Optional[float]
run_strat_json: Optional[str] = None
run_stopped: Optional[datetime] = None run_stopped: Optional[datetime] = None
run_paused: Optional[datetime] = None run_paused: Optional[datetime] = None
run_thread: Optional[object] = None run_thread: Optional[object] = None
@ -176,6 +178,7 @@ class RunArchive(BaseModel):
account: Account account: Account
bt_from: Optional[datetime] = None bt_from: Optional[datetime] = None
bt_to: Optional[datetime] = None bt_to: Optional[datetime] = None
strat_json: Optional[str] = None
stratvars: Optional[dict] = None stratvars: Optional[dict] = None
settings: Optional[dict] = None settings: Optional[dict] = None
ilog_save: Optional[bool] = False ilog_save: Optional[bool] = False

View File

@ -41,10 +41,11 @@ def get_all_runners():
if len(db.runners) > 0: if len(db.runners) > 0:
#print(db.runners) #print(db.runners)
for i in db.runners: for i in db.runners:
i.run_profit = round(float(i.run_instance.state.profit),2) if i.run_instance:
i.run_trade_count = len(i.run_instance.state.tradeList) i.run_profit = round(float(i.run_instance.state.profit),2)
i.run_positions = i.run_instance.state.positions i.run_trade_count = len(i.run_instance.state.tradeList)
i.run_avgp = round(float(i.run_instance.state.avgp),3) i.run_positions = i.run_instance.state.positions
i.run_avgp = round(float(i.run_instance.state.avgp),3)
return (0, db.runners) return (0, db.runners)
else: else:
return (0, []) return (0, [])
@ -385,6 +386,7 @@ def run_stratin(id: UUID, runReq: RunRequest):
run_symbol = symbol, run_symbol = symbol,
run_note = runReq.note, run_note = runReq.note,
run_stop_ev = se, run_stop_ev = se,
run_strat_json = runReq.strat_json,
run_thread = vlakno, run_thread = vlakno,
run_account = runReq.account, run_account = runReq.account,
run_ilog_save = runReq.ilog_save, run_ilog_save = runReq.ilog_save,
@ -444,6 +446,7 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
ilog_save=runner.run_ilog_save, ilog_save=runner.run_ilog_save,
bt_from=bp_from, bt_from=bp_from,
bt_to = bp_to, bt_to = bp_to,
strat_json = runner.run_strat_json,
stratvars = strat.state.vars, stratvars = strat.state.vars,
settings = settings, settings = settings,
profit=round(float(strat.state.profit),2), profit=round(float(strat.state.profit),2),

View File

@ -3,6 +3,7 @@ import numpy as np
import pandas as pd import pandas as pd
from collections import deque from collections import deque
import typing import typing
from v2realbot.utils.utils import check_series, convert_to_numpy
def ema(data, period: int = 50, use_series=False): def ema(data, period: int = 50, use_series=False):
if check_series(data): if check_series(data):
@ -23,14 +24,3 @@ def sma(data, period: int = 50, use_series=False):
data = convert_to_numpy(data) data = convert_to_numpy(data)
sma = ti.sma(data, period=period) sma = ti.sma(data, period=period)
return pd.Series(sma) if use_series else sma return pd.Series(sma) if use_series else sma
def convert_to_numpy(data):
if isinstance(data, list) or isinstance(data, deque):
return np.fromiter(data, float)
elif isinstance(data, pd.Series):
return data.to_numpy()
return data
def check_series(data):
return isinstance(data, pd.Series)

View File

@ -20,20 +20,9 @@
#inspirovat se, pripadne vyzkouset i TAlib #inspirovat se, pripadne vyzkouset i TAlib
from typing import Any from typing import Any
import pandas as pd import pandas as pd
import tulipy as ti import tulipy as ti
from v2realbot.utils.utils import check_series, convert_to_numpy
def convert_to_numpy(data: Any):
if isinstance(data, list) or isinstance(data, deque):
return np.fromiter(data, float)
elif isinstance(data, pd.Series):
return data.to_numpy()
return data
def check_series(data: Any):
return isinstance(data, pd.Series)
def ema(data: Any, period: int = 50, use_series=False) -> Any: def ema(data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data): if check_series(data):

View File

@ -0,0 +1,102 @@
"""
Oscillator wrappers
Copyright (C) 2021 Brandon Fan
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from typing import Any
import numpy as np
import pandas as pd
import tulipy as ti
from v2realbot.utils.utils import check_series, convert_to_numpy
def rsi(data: Any, period: int = 14, round_rsi: bool = False, use_series=False) -> np.array:
""" Implements RSI Indicator """
if period >= len(data):
return pd.Series() if use_series else []
if check_series(data):
use_series = True
data = convert_to_numpy(data)
rsi_values = ti.rsi(data, period)
if round_rsi:
rsi_values = np.round(rsi_values, 2)
return pd.Series(rsi_values) if use_series else rsi_values
def aroon_oscillator(high_data: Any, low_data: Any, period=14, use_series=False):
if check_series(high_data) or check_series(low_data):
use_series = True
high_data = convert_to_numpy(high_data)
low_data = convert_to_numpy(low_data)
aroonsc = ti.aroonosc(high_data, low_data, period=period)
return pd.Series(aroonsc) if use_series else aroonsc
def chande_momentum_oscillator(data, period=14, use_series=False):
if check_series(data):
use_series = True
data = convert_to_numpy(data)
cmo = ti.cmo(data, period)
return pd.Series(cmo) if use_series else cmo
def absolute_price_oscillator(data, short_period=12, long_period=26, use_series=False):
if check_series(data):
use_series = True
data = convert_to_numpy(data)
apo = ti.apo(data, short_period, long_period)
return pd.Series(apo) if use_series else apo
def percentage_price_oscillator(data, short_period=12, long_period=26, use_series=False):
if check_series(data):
use_series = True
data = convert_to_numpy(data)
ppo = ti.ppo(data, short_period, long_period)
return pd.Series(ppo) if use_series else ppo
def stochastic_oscillator(high_data, low_data, close_data, pct_k_period=14, pct_k_slowing_period=3, pct_d_period=3,
use_series=False):
if check_series(high_data) or check_series(low_data) or check_series(close_data):
use_series = True
high_data = convert_to_numpy(high_data)
low_data = convert_to_numpy(low_data)
close_data = convert_to_numpy(close_data)
stoch = ti.stoch(high_data, low_data, close_data, pct_k_period, pct_k_slowing_period, pct_d_period)
return pd.Series(stoch) if use_series else stoch
def stochastic_rsi(data, period=14, smooth_pct_k=3, smooth_pct_d=3):
""" Calculates Stochoastic RSI Courteous of @lukazbinden
:param data:
:param period:
:param smooth_pct_k:
:param smooth_pct_d:
:return:
"""
# Calculate RSI
rsi_values = rsi(data, period=period, round_rsi=False)
# Calculate StochRSI
rsi_values = pd.Series(rsi_values)
stochrsi = (rsi_values - rsi_values.rolling(period).min()) / (
rsi_values.rolling(period).max() - rsi_values.rolling(period).min())
stochrsi_K = stochrsi.rolling(smooth_pct_k).mean()
stochrsi_D = stochrsi_K.rolling(smooth_pct_d).mean()
return round(rsi_values, 2), round(stochrsi_K * 100, 2), round(stochrsi_D * 100, 2)

View File

@ -170,7 +170,6 @@ class LiveInterface(GeneralInterface):
def get_open_orders(self, symbol: str, side: OrderSide = OrderSide.SELL): # -> list(Order): def get_open_orders(self, symbol: str, side: OrderSide = OrderSide.SELL): # -> list(Order):
getRequest = GetOrdersRequest(status=QueryOrderStatus.OPEN, side=side, symbols=[symbol]) getRequest = GetOrdersRequest(status=QueryOrderStatus.OPEN, side=side, symbols=[symbol])
try: try:
# Market order submit
orderlist = self.trading_client.get_orders(getRequest) orderlist = self.trading_client.get_orders(getRequest)
#list of Orders (orderlist[0].id) #list of Orders (orderlist[0].id)
return orderlist return orderlist

View File

@ -187,6 +187,7 @@
<th>trade</th> <th>trade</th>
<th>pos</th> <th>pos</th>
<th>pos_avgp</th> <th>pos_avgp</th>
<th>json</th>
<th>open</th> <th>open</th>
</tr> </tr>
</thead> </thead>
@ -235,7 +236,11 @@
<div class="form-group"> <div class="form-group">
<label for="stratvars" class="form-label">Stratvars</label> <label for="stratvars" class="form-label">Stratvars</label>
<textarea class="form-control" rows="4" id="editstratvars" name="stratvars"></textarea> <textarea class="form-control" rows="4" id="editstratvars" name="stratvars"></textarea>
</div> </div>
<div class="form-group">
<label for="strat_json" class="form-label">Strat JSON</label>
<textarea class="form-control" rows="4" id="editstratjson" name="stratjson"></textarea>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input type="submit" name="delete" id="editarchive" class="btn btn-primary" value="Edit" /> <input type="submit" name="delete" id="editarchive" class="btn btn-primary" value="Edit" />

View File

@ -47,7 +47,7 @@ function transform_data(data) {
var markers = [] var markers = []
var markers_line = [] var markers_line = []
var last_timestamp = 0.1 var last_timestamp = 0.1
var iterator = 0.001 var iterator = 0.002
data.trades.forEach((trade, index, array) => { data.trades.forEach((trade, index, array) => {
obj = {}; obj = {};
a_markers = {} a_markers = {}
@ -62,13 +62,15 @@ function transform_data(data) {
} }
if (last_timestamp == timestamp) { if (last_timestamp == timestamp) {
last_timestamp = timestamp last_timestamp = timestamp
console.log("DUPLICITA tradu", trade) console.log("DUPLICITA tradu aktual/predchozi/nasledujici", trade, data.trades[index-1], data.trades[index+1])
timestamp = timestamp + iterator console.log("původní timestamp je ",timestamp)
timestamp = parseFloat(timestamp) + iterator
console.log("nový timestamp je ",timestamp)
iterator += 0.001 iterator += 0.001
} }
else { else {
last_timestamp = timestamp last_timestamp = timestamp
iterator = 0.001 iterator = 0.002
} }
if (trade.order.side == "buy") { if (trade.order.side == "buy") {
@ -129,6 +131,8 @@ function transform_data(data) {
markers.sort(sorter) markers.sort(sorter)
markers_line.sort(sorter) markers_line.sort(sorter)
avgp_buy_line.sort(sorter)
avgp_markers.sort(sorter)
transformed["avgp_buy_line"] = avgp_buy_line transformed["avgp_buy_line"] = avgp_buy_line
transformed["avgp_markers"] = avgp_markers transformed["avgp_markers"] = avgp_markers
@ -213,7 +217,7 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
["1m", oneMinuteBars ], ["1m", oneMinuteBars ],
]); ]);
var switcherElement = createSimpleSwitcher(intervals, intervals[1], switch_to_interval); var switcherElement = createSimpleSwitcher(intervals, intervals[1], switch_to_interval);
//define tooltip //define tooltip
const container1 = document.getElementById('chart'); const container1 = document.getElementById('chart');
@ -260,9 +264,15 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
if (interval == native_resolution) { if (interval == native_resolution) {
//indicators are in native resolution only //indicators are in native resolution only
display_indicators(data); display_indicators(data);
var indbuttonElement = populate_indicator_buttons();
container1.append(indbuttonElement);
} }
else { else {
remove_indicators(); remove_indicators();
btnElement = document.getElementById("indicatorsButtons")
if (btnElement) {
container1.removeChild(btnElement);
}
} }
display_buy_markers(); display_buy_markers();

View File

@ -42,6 +42,7 @@ $(document).ready(function () {
$('#editidarchive').val(row.id); $('#editidarchive').val(row.id);
$('#editnote').val(row.note); $('#editnote').val(row.note);
$('#editstratvars').val(JSON.stringify(row.stratvars,null,2)); $('#editstratvars').val(JSON.stringify(row.stratvars,null,2));
$('#editstratjson').val(row.strat_json);
}); });
//show button //show button
@ -176,6 +177,7 @@ var archiveRecords =
{data: 'trade_count', visible: true}, {data: 'trade_count', visible: true},
{data: 'end_positions', visible: true}, {data: 'end_positions', visible: true},
{data: 'end_positions_avgp', visible: true}, {data: 'end_positions_avgp', visible: true},
{data: 'strat_json', visible: false},
{data: 'open_orders', visible: true} {data: 'open_orders', visible: true}
], ],
paging: false, paging: false,

View File

@ -412,7 +412,7 @@ var stratinRecords =
{data: 'name'}, {data: 'name'},
{data: 'symbol'}, {data: 'symbol'},
{data: 'class_name', visible: false}, {data: 'class_name', visible: false},
{data: 'script', visible: false}, {data: 'script', visible: true},
{data: 'open_rush', visible: false}, {data: 'open_rush', visible: false},
{data: 'close_rush', visible: false}, {data: 'close_rush', visible: false},
{data: 'stratvars_conf', visible: false}, {data: 'stratvars_conf', visible: false},
@ -531,6 +531,24 @@ $("#runModal").on('submit','#runForm', function(event){
// $('#subscribe').prop('checked') // $('#subscribe').prop('checked')
if (formData.bt_from == "") {delete formData["bt_from"];} if (formData.bt_from == "") {delete formData["bt_from"];}
if (formData.bt_to == "") {delete formData["bt_to"];} if (formData.bt_to == "") {delete formData["bt_to"];}
//create strat_json - snapshot of stratin
row = stratinRecords.row('.selected').data();
const rec = new Object()
rec.id2 = parseInt(row.id2);
rec.name = row.name;
rec.symbol = row.symbol;
rec.class_name = row.class_name;
rec.script = row.script;
rec.open_rush = row.open_rush;
rec.close_rush = row.close_rush;
rec.stratvars_conf = row.stratvars_conf;
rec.add_data_conf = row.add_data_conf;
rec.note = row.note;
rec.history = "";
strat_json = JSON.stringify(rec);
formData.strat_json = strat_json
jsonString = JSON.stringify(formData); jsonString = JSON.stringify(formData);
//console.log(jsonString) //console.log(jsonString)
//window.alert(jsonString); //window.alert(jsonString);

View File

@ -14,8 +14,17 @@ settings = {}
settings settings
//ostatni indicatory nez vwap, volume a bary //ostatni indicatory nez vwap, volume a bary
indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false}, indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
{name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false}, {name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "middle", lastValueVisible: false},
{name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},] {name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
{name: "emaSlow", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
{name: "emaFast", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
{name: "RSI14", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "RSI5", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "aroon", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "apo", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "ppo", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "stoch2", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "stoch1", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},]
function get_ind_config(indName) { function get_ind_config(indName) {
const i = indConfig.findIndex(e => e.name === indName); const i = indConfig.findIndex(e => e.name === indName);
@ -197,6 +206,39 @@ function initialize_vwap() {
}) })
} }
function populate_indicator_buttons() {
var buttonElement = document.createElement('div');
buttonElement.id = "indicatorsButtons"
buttonElement.classList.add('switcher');
indList.forEach(function (item, index) {
var itemEl = document.createElement('button');
itemEl.innerText = item.name;
itemEl.id = "IND"+index;
itemEl.style.color = item.series.options().color;
itemEl.classList.add('switcher-item');
itemEl.classList.add('switcher-active-item');
itemEl.addEventListener('click', function() {
onItemClicked1(index);
});
buttonElement.appendChild(itemEl);
});
function onItemClicked1(index) {
vis = true;
const elem = document.getElementById("IND"+index);
if (elem.classList.contains("switcher-active-item")) {
vis = false;
}
elem.classList.toggle("switcher-active-item");
indList[index].series.applyOptions({
visible: vis });
}
return buttonElement;
}
//range switch pro chart https://jsfiddle.net/TradingView/qrb9a850/ //range switch pro chart https://jsfiddle.net/TradingView/qrb9a850/
function createSimpleSwitcher(items, activeItem, activeItemChangedCallback) { function createSimpleSwitcher(items, activeItem, activeItemChangedCallback) {
var switcherElement = document.createElement('div'); var switcherElement = document.createElement('div');

View File

@ -341,7 +341,7 @@ pre {
} }
.switcher-item:hover { .switcher-item:hover {
background-color: #f2f3f5; background-color: #f2f3f521;
} }
.switcher-active-item { .switcher-active-item {

View File

@ -19,6 +19,9 @@ from enum import Enum
#from v2realbot.enums.enums import Order #from v2realbot.enums.enums import Order
from v2realbot.common.model import Order as btOrder, TradeUpdate as btTradeUpdate from v2realbot.common.model import Order as btOrder, TradeUpdate as btTradeUpdate
from alpaca.trading.models import Order, TradeUpdate from alpaca.trading.models import Order, TradeUpdate
import numpy as np
import pandas as pd
from collections import deque
def safe_get(collection, key, default=None): def safe_get(collection, key, default=None):
"""Get values from a collection without raising errors""" """Get values from a collection without raising errors"""
@ -239,3 +242,13 @@ def list_replace_value(l: list, old: str, new) -> list:
x.append(e) x.append(e)
return x return x
def convert_to_numpy(data):
if isinstance(data, list) or isinstance(data, deque):
return np.fromiter(data, float)
elif isinstance(data, pd.Series):
return data.to_numpy()
return data
def check_series(data):
return isinstance(data, pd.Series)