bugfixes a pridana moznost z archivu mit json
This commit is contained in:
487
v2realbot/ENTRY_VykladaciTest.py
Normal file
487
v2realbot/ENTRY_VykladaciTest.py
Normal 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
|
||||||
|
|
||||||
|
|
||||||
521
v2realbot/ENTRY_Vykladaci_RSI.py
Normal file
521
v2realbot/ENTRY_Vykladaci_RSI.py
Normal 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()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
@ -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:
|
||||||
|
|||||||
Binary file not shown.
@ -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
|
||||||
|
|||||||
@ -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),
|
||||||
|
|||||||
Binary file not shown.
@ -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)
|
|
||||||
@ -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):
|
||||||
|
|||||||
102
v2realbot/indicators/oscillators.py
Normal file
102
v2realbot/indicators/oscillators.py
Normal 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)
|
||||||
Binary file not shown.
@ -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
|
||||||
|
|||||||
@ -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" />
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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');
|
||||||
|
|||||||
@ -341,7 +341,7 @@ pre {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.switcher-item:hover {
|
.switcher-item:hover {
|
||||||
background-color: #f2f3f5;
|
background-color: #f2f3f521;
|
||||||
}
|
}
|
||||||
|
|
||||||
.switcher-active-item {
|
.switcher-active-item {
|
||||||
|
|||||||
Binary file not shown.
@ -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)
|
||||||
Reference in New Issue
Block a user