refactor plneni time u indikatoru, v next upd
This commit is contained in:
@ -237,10 +237,10 @@ def next(data, state: StrategyState):
|
||||
#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))
|
||||
state.indicators.ema[-1]=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)
|
||||
#state.indicators.ema[-1]=0
|
||||
|
||||
#EMA SLOW
|
||||
try:
|
||||
@ -249,11 +249,11 @@ def next(data, state: StrategyState):
|
||||
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.indicators.emaSlow[-1]=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)
|
||||
#state.indicators.emaSlow.append(0)
|
||||
|
||||
|
||||
#EMA FAST
|
||||
@ -263,11 +263,11 @@ def next(data, state: StrategyState):
|
||||
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.indicators.emaFast[-1]=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)
|
||||
#state.indicators.emaFast.append(0)
|
||||
|
||||
|
||||
#RSI14
|
||||
@ -352,7 +352,7 @@ def next(data, state: StrategyState):
|
||||
#výpočet úhlu
|
||||
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
|
||||
slope = round(slope, 4)
|
||||
state.indicators.slope.append(slope)
|
||||
state.indicators.slope[-1]=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)
|
||||
@ -362,7 +362,7 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=slopeMA
|
||||
|
||||
state.ilog(e=f"{slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-10:])
|
||||
|
||||
@ -371,8 +371,8 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=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))
|
||||
|
||||
@ -303,10 +303,10 @@ def next(data, state: StrategyState):
|
||||
#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))
|
||||
state.indicators.ema[-1]=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)
|
||||
state.indicators.ema[-1]=0
|
||||
|
||||
#RSI14 INDICATOR
|
||||
try:
|
||||
@ -320,13 +320,13 @@ def next(data, state: StrategyState):
|
||||
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.indicators.RSI14[-1]=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)
|
||||
#state.indicators.RSI14.append(0)
|
||||
|
||||
|
||||
#SLOPE INDICATOR
|
||||
@ -349,7 +349,7 @@ def next(data, state: StrategyState):
|
||||
#výpočet úhlu
|
||||
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
|
||||
slope = round(slope, 4)
|
||||
state.indicators.slope.append(slope)
|
||||
state.indicators.slope[-1]=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)
|
||||
@ -359,7 +359,7 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=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:])
|
||||
|
||||
@ -368,8 +368,8 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=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))
|
||||
|
||||
525
v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py
Normal file
525
v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py
Normal file
@ -0,0 +1,525 @@
|
||||
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.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||
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, get_tick
|
||||
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__))))
|
||||
""""
|
||||
Využívá: StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||
|
||||
Kopie RSI Normalizovane Vykladaci navíc s řízením prodeje.
|
||||
Nepoužíváme LIMITKU.
|
||||
|
||||
Required CBAR. (pouze se změnou ceny)
|
||||
|
||||
nepotvrzený CBAR bez minticku (pouze se změnou ceny)
|
||||
- se používá pro žízení prodeje
|
||||
|
||||
potvrzený CBAR
|
||||
- se používá pro 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",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",state.vars.profit)
|
||||
cena = float(state.avgp)
|
||||
#v MYSELL hrajeme i na 3 desetinna cisla - TBD mozna hrat jen na 5ky (0.125, 0.130, 0.135 atp.)
|
||||
if is_defensive_mode():
|
||||
return price2dec(cena+get_tick(cena,float(def_profit)),3)
|
||||
else:
|
||||
return price2dec(cena+get_tick(cena,float(state.vars.profit)),3)
|
||||
|
||||
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 = {}
|
||||
#zaciname s cistym stitem
|
||||
state.vars.limitka = None
|
||||
state.vars.limitka_price = None
|
||||
for o in orderlist:
|
||||
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
|
||||
pendingbuys_new[str(o.id)]=float(o.limit_price)
|
||||
|
||||
if pendingbuys_new != state.vars.pendingbuys:
|
||||
state.ilog(e="Rozdilna PB prepsana", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys)
|
||||
print("ROZDILNA PENDINGBUYS přepsána")
|
||||
print("OLD",state.vars.pendingbuys)
|
||||
state.vars.pendingbuys = unpackb(packb(pendingbuys_new))
|
||||
print("NEW", state.vars.pendingbuys)
|
||||
else:
|
||||
print("PENDINGBUYS sedí - necháváme", state.vars.pendingbuys)
|
||||
state.ilog(e="PB sedi nechavame", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys)
|
||||
print("OLD jevylozeno", state.vars.jevylozeno)
|
||||
if len(state.vars.pendingbuys) > 0:
|
||||
state.vars.jevylozeno = 1
|
||||
else:
|
||||
state.vars.jevylozeno = 0
|
||||
print("NEW jevylozeno", state.vars.jevylozeno)
|
||||
state.ilog(e="Nove jevylozeno", msg=state.vars.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 - get_tick(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
|
||||
|
||||
def eval_sell():
|
||||
""""
|
||||
TBD
|
||||
Když je RSI nahoře tak neprodávat, dokud 1) RSI neprestane stoupat 2)nedosahne to nad im not greedy limit
|
||||
"""
|
||||
##mame pozice
|
||||
##aktualni cena je vetsi nebo rovna cene limitky
|
||||
#muzeme zde jet i na pulcenty
|
||||
curr_price = float(data['close'])
|
||||
state.ilog(e="Eval SELL", price=curr_price, pos=state.positions, sell_in_progress=state.vars.sell_in_progress)
|
||||
if int(state.positions) > 0 and state.vars.sell_in_progress is False:
|
||||
goal_price = get_limitka_price()
|
||||
state.ilog(e=f"Goal price {goal_price}")
|
||||
if curr_price>=goal_price:
|
||||
state.interface.sell(size=state.positions)
|
||||
state.vars.sell_in_progress = True
|
||||
state.ilog(e=f"market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress)
|
||||
|
||||
#na urovni CBARU mame zajisteno, ze update prichazi pri zmene ceny
|
||||
#v kazde iteraci testujeme sell
|
||||
#pri confirmed tesutjeme i buy
|
||||
state.ilog(e="-----")
|
||||
eval_sell()
|
||||
|
||||
|
||||
conf_bar = data['confirmed']
|
||||
#for CBAR TICK and VOLUME change info
|
||||
#price change vs Volume
|
||||
tick_price = data['close']
|
||||
tick_volume = data['volume'] - state.vars.last_tick_volume
|
||||
|
||||
#pouze potvrzovací BAR CBARu, mozna id confirmed = 1, pak ignorovat
|
||||
if tick_volume == 0:
|
||||
pass
|
||||
|
||||
##naplneni indikatoru vnitrniho CBAR tick price
|
||||
##pozor CBAR identifikatory jsou ukladane do historie az pro konfirmnuty bar
|
||||
try:
|
||||
state.indicators.tick_price[-1] = tick_price
|
||||
state.indicators.tick_volume[-1] = tick_volume
|
||||
except:
|
||||
pass
|
||||
|
||||
state.ilog(e=f"TICK PRICE {tick_price} VOLUME {tick_volume} {conf_bar=}", last_price=state.vars.last_tick_price, last_volume=state.vars.last_tick_volume)
|
||||
|
||||
|
||||
state.vars.last_tick_price = tick_price
|
||||
state.vars.last_tick_volume = data['volume']
|
||||
#pri potvrzem CBARu nulujeme counter volume
|
||||
if conf_bar == 1:
|
||||
state.vars.last_tick_volume = 0
|
||||
state.vars.next_new = 1
|
||||
|
||||
|
||||
|
||||
# if data['confirmed'] == 0:
|
||||
# state.ilog(e="CBAR unconfirmed - returned", msg=str(data))
|
||||
# #TBD zde muzeme i nakupovat
|
||||
# #indikatory pocitat, ale neukladat do historie
|
||||
# return 0
|
||||
# #confirmed
|
||||
# else:
|
||||
# state.ilog(e="CBAR confirmed - continue", msg=str(data))
|
||||
|
||||
#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[-1]=trunc(ema_value[-1],3)
|
||||
except Exception as e:
|
||||
state.ilog(e="EMA nechavame 0", message=str(e)+format_exc())
|
||||
#state.indicators.ema[-1]=(0)
|
||||
|
||||
#RSI14 INDICATOR
|
||||
try:
|
||||
##mame v atributech nastaveni?
|
||||
rsi_dont_buy_above = safe_get(state.vars, "rsi_dont_buy_above",50)
|
||||
rsi_buy_signal_conf = safe_get(state.vars, "rsi_buy_signal_below",40)
|
||||
rsi_buy_signal = False
|
||||
rsi_dont_buy = False
|
||||
rsi_length = 2
|
||||
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[-1]=rsi_value
|
||||
rsi_dont_buy = rsi_value > rsi_dont_buy_above
|
||||
rsi_buy_signal = rsi_value < rsi_buy_signal_conf
|
||||
state.ilog(e=f"RSI{rsi_value} {rsi_length=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.indicators.RSI14[-5:])
|
||||
except Exception as e:
|
||||
state.ilog(e=f"RSI {rsi_length=} nechavame 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 - a jeho normalizace
|
||||
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
|
||||
slope = round(slope, 4)
|
||||
state.indicators.slope[-1]=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[-1]=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.slopeMA[-1]=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()
|
||||
|
||||
if int(state.positions) >= state.vars.maxpozic:
|
||||
state.ilog(e="Max pos reached")
|
||||
return 0
|
||||
|
||||
|
||||
#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:
|
||||
state.ilog(e="BUY SIGNAL")
|
||||
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) + get_tick(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.vars['sell_in_progress'] = False
|
||||
state.vars.last_tick_price = 0
|
||||
state.vars.last_tick_volume = 0
|
||||
state.vars.next_new = 0
|
||||
state.indicators['tick_price'] = []
|
||||
state.indicators['tick_volume'] = []
|
||||
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 = StrategyOrderLimitVykladaciNormalizedMYSELL(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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -302,10 +302,10 @@ def next(data, state: StrategyState):
|
||||
#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))
|
||||
state.indicators.ema[-1]=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)
|
||||
#state.indicators.ema[-1]=0
|
||||
|
||||
#RSI14 INDICATOR
|
||||
try:
|
||||
@ -318,13 +318,13 @@ def next(data, state: StrategyState):
|
||||
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.indicators.RSI14[-1]=rsi_value
|
||||
rsi_dont_buy = rsi_value > rsi_dont_buy_above
|
||||
rsi_buy_signal = rsi_value < rsi_buy_signal_conf
|
||||
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)
|
||||
#state.indicators.RSI14[-1]=0
|
||||
|
||||
|
||||
#SLOPE INDICATOR
|
||||
@ -347,7 +347,7 @@ def next(data, state: StrategyState):
|
||||
#výpočet úhlu
|
||||
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
|
||||
slope = round(slope, 4)
|
||||
state.indicators.slope.append(slope)
|
||||
state.indicators.slope[-1]=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)
|
||||
@ -357,7 +357,7 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=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:])
|
||||
|
||||
@ -366,8 +366,8 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=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))
|
||||
|
||||
@ -310,10 +310,10 @@ def next(data, state: StrategyState):
|
||||
#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))
|
||||
state.indicators.ema[-1]=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)
|
||||
state.indicators.ema[-1]=0
|
||||
|
||||
#SLOPE INDICATOR
|
||||
#úhel stoupání a klesání vyjádřený mezi -1 až 1
|
||||
@ -335,7 +335,7 @@ def next(data, state: StrategyState):
|
||||
#výpočet úhlu
|
||||
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
|
||||
slope = round(slope, 4)
|
||||
state.indicators.slope.append(slope)
|
||||
state.indicators.slope[-1]=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)
|
||||
@ -345,7 +345,7 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=slopeMA
|
||||
|
||||
state.ilog(e=f"{slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-10:])
|
||||
|
||||
@ -354,8 +354,8 @@ def next(data, state: StrategyState):
|
||||
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.indicators.slopeMA[-1]=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))
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -34,7 +34,7 @@ class RecordType(str, Enum):
|
||||
"""
|
||||
|
||||
BAR = "bar"
|
||||
CBAR = "continuosbar"
|
||||
CBAR = "cbar"
|
||||
TRADE = "trade"
|
||||
|
||||
class Mode(str, Enum):
|
||||
|
||||
Binary file not shown.
@ -79,9 +79,10 @@ class TradeAggregator:
|
||||
## 22.3. - dal jsem pryc i contingency trades [' ', '7', 'V'] - nasel jsem obchod o 30c mimo
|
||||
## dán pryč P - prior reference time + 25centu mimo, {'t': '2023-04-12T19:45:08.63257344Z', 'x': 'D', 'p': 28.68, 's': 1000, 'c': [' ', 'P'], 'i': 71693108525109, 'z': 'A'},
|
||||
## Q - jsou v pohode, oteviraci trady, ale O jsou jejich duplikaty
|
||||
## přidán W - average price trade, U - Extended hours - sold out of sequence
|
||||
try:
|
||||
for i in data['c']:
|
||||
if i in ('C','O','4','B','7','V','P'): return 0
|
||||
if i in ('C','O','4','B','7','V','P','W','U'): return 0
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
@ -196,6 +197,11 @@ class TradeAggregator:
|
||||
"index": self.barindex
|
||||
}
|
||||
|
||||
#je cena stejna od predchoziho tradu? pro nepotvrzeny cbar vracime jen pri zmene ceny
|
||||
if self.last_price == data['p']:
|
||||
diff_price = False
|
||||
else:
|
||||
diff_price = True
|
||||
self.last_price = data['p']
|
||||
|
||||
#spočteme vwap - potřebujeme předchozí hodnoty
|
||||
@ -268,7 +274,12 @@ class TradeAggregator:
|
||||
#doplnime prubezny vwap
|
||||
self.newBar['vwap'] = self.vwaphelper / self.newBar['volume']
|
||||
#print(self.newBar)
|
||||
return self.newBar
|
||||
|
||||
#pro (nepotvrzeny) cbar vracime jen pri zmene ceny
|
||||
if diff_price is True:
|
||||
return self.newBar
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
@ -332,28 +332,53 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
|
||||
});
|
||||
|
||||
if (conf.embed) {
|
||||
obj.series = chart.addLineSeries({
|
||||
color: colors.shift(),
|
||||
priceScaleId: conf.priceScaleId,
|
||||
title: (conf.titlevisible?conf.name:""),
|
||||
lineWidth: 1
|
||||
});
|
||||
|
||||
//toto nejak vymyslet konfiguracne, additional threshold lines
|
||||
if (key == "slopeMA") {
|
||||
//natvrdo nakreslime lajnu pro min angle
|
||||
//TODO predelat na configuracne
|
||||
const minSlopeLineOptopns = {
|
||||
price: data.statinds.angle.minimum_slope,
|
||||
color: '#b67de8',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // LineStyle.Dotted
|
||||
axisLabelVisible: true,
|
||||
title: "max:",
|
||||
};
|
||||
if (conf.histogram) {
|
||||
|
||||
obj.series = chart.addHistogramSeries({
|
||||
title: (conf.titlevisible?conf.name:""),
|
||||
color: colors.shift(),
|
||||
priceFormat: {type: 'volume'},
|
||||
priceScaleId: conf.priceScaleId,
|
||||
lastValueVisible: conf.lastValueVisible,
|
||||
priceScaleId: conf.priceScaleId});
|
||||
|
||||
obj.series.priceScale().applyOptions({
|
||||
// set the positioning of the volume series
|
||||
scaleMargins: {
|
||||
top: 0.7, // highest point of the series will be 70% away from the top
|
||||
bottom: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const minSlopeLine = obj.series.createPriceLine(minSlopeLineOptopns);
|
||||
}
|
||||
else {
|
||||
|
||||
obj.series = chart.addLineSeries({
|
||||
color: colors.shift(),
|
||||
priceScaleId: conf.priceScaleId,
|
||||
title: (conf.titlevisible?conf.name:""),
|
||||
lineWidth: 1
|
||||
});
|
||||
|
||||
//toto nejak vymyslet konfiguracne, additional threshold lines
|
||||
if (key == "slopeMA") {
|
||||
//natvrdo nakreslime lajnu pro min angle
|
||||
//TODO predelat na configuracne
|
||||
const minSlopeLineOptopns = {
|
||||
price: data.statinds.angle.minimum_slope,
|
||||
color: '#b67de8',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // LineStyle.Dotted
|
||||
axisLabelVisible: true,
|
||||
title: "max:",
|
||||
};
|
||||
|
||||
const minSlopeLine = obj.series.createPriceLine(minSlopeLineOptopns);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//INDICATOR on new pane
|
||||
else { console.log("not implemented")}
|
||||
|
||||
@ -326,7 +326,7 @@ var archiveRecords =
|
||||
style: 'multi',
|
||||
selector: 'td'
|
||||
},
|
||||
// paging: true,
|
||||
paging: true,
|
||||
// lengthChange: false,
|
||||
// select: true,
|
||||
// createdRow: function( row, data, dataIndex){
|
||||
|
||||
@ -275,13 +275,35 @@ function connect(event) {
|
||||
//MOVE TO UTILS ro reuse??
|
||||
if (conf && conf.display) {
|
||||
if (conf.embed) {
|
||||
obj.series = chart.addLineSeries({
|
||||
color: colors.shift(),
|
||||
priceScaleId: conf.priceScaleId,
|
||||
lastValueVisible: conf.lastValueVisible,
|
||||
title: (conf.titlevisible?conf.name:""),
|
||||
lineWidth: 1
|
||||
});
|
||||
|
||||
if (conf.histogram) {
|
||||
|
||||
obj.series = chart.addHistogramSeries({
|
||||
title: (conf.titlevisible?conf.name:""),
|
||||
color: colors.shift(),
|
||||
priceFormat: {type: 'volume'},
|
||||
priceScaleId: conf.priceScaleId,
|
||||
lastValueVisible: conf.lastValueVisible,
|
||||
priceScaleId: conf.priceScaleId});
|
||||
|
||||
obj.series.priceScale().applyOptions({
|
||||
// set the positioning of the volume series
|
||||
scaleMargins: {
|
||||
top: 0.7, // highest point of the series will be 70% away from the top
|
||||
bottom: 0,
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
obj.series = chart.addLineSeries({
|
||||
color: colors.shift(),
|
||||
priceScaleId: conf.priceScaleId,
|
||||
lastValueVisible: conf.lastValueVisible,
|
||||
title: (conf.titlevisible?conf.name:""),
|
||||
lineWidth: 1
|
||||
});
|
||||
}
|
||||
|
||||
//tady add data
|
||||
obj.series.update({
|
||||
|
||||
@ -14,6 +14,8 @@ settings = {}
|
||||
settings
|
||||
//ostatni indicatory nez vwap, volume a bary
|
||||
indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
||||
{name: "tick_volume", histogram: true, titlevisible: true, embed: true, display: true, priceScaleId: '', lastValueVisible: false},
|
||||
{name: "tick_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
||||
{name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "middle", 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},
|
||||
@ -171,7 +173,7 @@ function initialize_chart() {
|
||||
|
||||
//mozna atributy last value visible
|
||||
function intitialize_candles() {
|
||||
candlestickSeries = chart.addCandlestickSeries({ lastValueVisible: false, priceLineWidth:1, priceLineColor: "red", priceFormat: { type: 'price', precision: 2, minMove: 0.01 }});
|
||||
candlestickSeries = chart.addCandlestickSeries({ lastValueVisible: false, priceLineWidth:1, priceLineColor: "red", priceFormat: { type: 'price', precision: 3, minMove: 0.005 }});
|
||||
candlestickSeries.priceScale().applyOptions({
|
||||
scaleMargins: {
|
||||
top: 0.1, // highest point of the series will be 10% away from the top
|
||||
|
||||
@ -0,0 +1,173 @@
|
||||
from v2realbot.strategy.base import Strategy
|
||||
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial, safe_get, get_tick
|
||||
from v2realbot.utils.tlog import tlog, tlog_exception
|
||||
from v2realbot.enums.enums import Mode, Order, Account, RecordType
|
||||
from alpaca.trading.models import TradeUpdate
|
||||
from alpaca.trading.enums import TradeEvent, OrderStatus
|
||||
from v2realbot.indicators.indicators import ema
|
||||
import json
|
||||
#from rich import print
|
||||
from random import randrange
|
||||
from alpaca.common.exceptions import APIError
|
||||
import copy
|
||||
from threading import Event
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
class StrategyOrderLimitVykladaciNormalizedMYSELL(Strategy):
|
||||
def __init__(self, name: str, symbol: str, next: callable, init: callable, account: Account, mode: Mode = Mode.PAPER, stratvars: AttributeDict = None, open_rush: int = 30, close_rush: int = 30, pe: Event = None, se: Event = None, runner_id: UUID = None, ilog_save: bool = False) -> None:
|
||||
super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se, runner_id, ilog_save)
|
||||
|
||||
async def orderUpdateBuy(self, data: TradeUpdate):
|
||||
o: Order = data.order
|
||||
##nejak to vymyslet, aby se dal poslat cely Trade a serializoval se
|
||||
self.state.ilog(e="Příchozí BUY notif", msg=o.status, trade=json.loads(json.dumps(data, default=json_serial)))
|
||||
if o.status == OrderStatus.FILLED or o.status == OrderStatus.CANCELED:
|
||||
|
||||
#pokud existuje objednavka v pendingbuys - vyhodime ji
|
||||
if self.state.vars.pendingbuys.pop(str(o.id), False):
|
||||
self.state.ilog(e="Příchozí BUY notif - mazeme ji z pb", msg=o.status, status=o.status, orderid=str(o.id), pb=self.state.vars.pendingbuys)
|
||||
print("limit buy filled or cancelled. Vyhazujeme z pendingbuys.")
|
||||
#ic(self.state.vars.pendingbuys)
|
||||
|
||||
if data.event == TradeEvent.FILL or data.event == TradeEvent.PARTIAL_FILL:
|
||||
#ic("vstupujeme do orderupdatebuy")
|
||||
print(data)
|
||||
#dostavame zde i celkové akutální množství - ukládáme
|
||||
self.state.positions = data.position_qty
|
||||
self.state.avgp, self.state.positions = self.state.interface.pos()
|
||||
|
||||
async def orderUpdateSell(self, data: TradeUpdate):
|
||||
|
||||
self.state.ilog(e="Příchozí SELL notif", msg=data.order.status, trade=json.loads(json.dumps(data, default=json_serial)))
|
||||
#PROFIT
|
||||
#profit pocitame z TradeUpdate.price a TradeUpdate.qty - aktualne provedene mnozstvi a cena
|
||||
#naklady vypocteme z prumerne ceny, kterou mame v pozicich
|
||||
if data.event == TradeEvent.FILL or data.event == TradeEvent.PARTIAL_FILL:
|
||||
if data.event == TradeEvent.FILL:
|
||||
self.state.vars.sell_in_progress = False
|
||||
|
||||
sold_amount = data.qty * data.price
|
||||
#podle prumerne ceny, kolik stalo toto mnozstvi
|
||||
avg_costs = float(self.state.avgp) * float(data.qty)
|
||||
if avg_costs == 0:
|
||||
self.state.ilog(e="ERR: Nemame naklady na PROFIT, AVGP je nula. Zaznamenano jako 0", msg="naklady=utrzena cena. TBD opravit.")
|
||||
avg_costs = sold_amount
|
||||
|
||||
trade_profit = (sold_amount - avg_costs)
|
||||
self.state.profit += trade_profit
|
||||
self.state.ilog(e=f"SELL notif - PROFIT:{round(float(trade_profit),3)} celkem:{round(float(self.state.profit),3)}", msg=str(data.event), sold_amount=sold_amount, avg_costs=avg_costs, trade_qty=data.qty, trade_price=data.price, orderid=str(data.order.id))
|
||||
|
||||
#update pozic, v trade update je i pocet zbylych pozic
|
||||
old_avgp = self.state.avgp
|
||||
old_pos = self.state.positions
|
||||
self.state.positions = int(data.position_qty)
|
||||
if int(data.position_qty) == 0:
|
||||
self.state.avgp = 0
|
||||
self.state.ilog(e="SELL notifikace "+str(data.order.status), msg="update pozic", old_avgp=old_avgp, old_pos=old_pos, avgp=self.state.avgp, pos=self.state.positions, orderid=str(data.order.id))
|
||||
#self.state.avgp, self.state.positions = self.interface.pos()
|
||||
|
||||
if data.event == TradeEvent.FILL or data.event == TradeEvent.CANCELED:
|
||||
print("Příchozí SELL notifikace - complete FILL nebo CANCEL", data.event)
|
||||
#muzeme znovu nakupovat, mazeme limitku, blockbuy a pendingbuys
|
||||
#self.state.blockbuy = 0
|
||||
|
||||
#ic("notifikace sell mazeme limitku a update pozic")
|
||||
#updatujeme pozice
|
||||
self.state.avgp, self.state.positions = self.interface.pos()
|
||||
#ic(self.state.avgp, self.state.positions)
|
||||
self.state.vars.limitka = None
|
||||
self.state.vars.limitka_price = None
|
||||
self.state.vars.lastbuyindex = -5
|
||||
self.state.vars.jevylozeno = 0
|
||||
await self.state.cancel_pending_buys()
|
||||
self.state.ilog(e="Příchozí SELL - FILL nebo CANCEL - mazeme limitku a pb", msg=data.order.status, orderid=str(data.order.id), pb=self.state.vars.pendingbuys)
|
||||
|
||||
#this parent method is called by strategy just once before waiting for first data
|
||||
def strat_init(self):
|
||||
#ic("strat INI function")
|
||||
#lets connect method overrides
|
||||
self.state.buy = self.buy
|
||||
self.state.buy_l = self.buy_l
|
||||
self.state.cancel_pending_buys = self.cancel_pending_buys
|
||||
|
||||
#overidden methods
|
||||
def buy(self, size = None, repeat: bool = False):
|
||||
print("overriden method to size&check maximum ")
|
||||
if int(self.state.positions) >= self.state.vars.maxpozic:
|
||||
self.state.ilog(e="buy Maxim mnozstvi naplneno", positions=self.state.positions)
|
||||
print("max mnostvi naplneno")
|
||||
return 0
|
||||
if size is None:
|
||||
sizer = self.state.vars.chunk
|
||||
else:
|
||||
sizer = size
|
||||
|
||||
self.state.blockbuy = 1
|
||||
self.state.vars.lastbuyindex = self.state.bars['index'][-1]
|
||||
self.state.ilog(e="send MARKET buy to if", msg="S:"+str(size), ltp=self.state.interface.get_last_price(self.state.symbol))
|
||||
return self.state.interface.buy(size=sizer)
|
||||
|
||||
def buy_l(self, price: float = None, size = None, repeat: bool = False):
|
||||
print("entering overriden BUY")
|
||||
if int(self.state.positions) >= self.state.vars.maxpozic:
|
||||
self.state.ilog(e="buyl Maxim mnozstvi naplneno", price=price, size=size, curr_positions=self.state.positions)
|
||||
return 0
|
||||
if size is None: size=self.state.vars.chunk
|
||||
if price is None: price=price2dec((self.state.interface.get_last_price(self.symbol)))
|
||||
#ic(price)
|
||||
print("odesilame LIMIT s cenou/qty", price, size)
|
||||
self.state.ilog(e="send LIMIT buy to if", msg="S:"+str(size)+" P:"+str(price), price=price, size=size)
|
||||
order = self.state.interface.buy_l(price=price, size=size)
|
||||
if order != -1:
|
||||
print("ukladame pendingbuys")
|
||||
self.state.vars.pendingbuys[str(order)]=price
|
||||
self.state.blockbuy = 1
|
||||
self.state.vars.lastbuyindex = self.state.bars['index'][-1]
|
||||
#ic(self.state.blockbuy)
|
||||
#ic(self.state.vars.lastbuyindex)
|
||||
self.state.ilog(e="Odeslan buy_l a ulozeno do pb", order=str(order), pb=self.state.vars.pendingbuys)
|
||||
else:
|
||||
self.state.ilog(e="Chyba - nepodarilo se odeslat buy_l - nebylo ulozeno do pb", order=str(order), pb=self.state.vars.pendingbuys)
|
||||
|
||||
async def cancel_pending_buys(self):
|
||||
print("cancel pending buys called.")
|
||||
self.state.ilog(e="Rusime pendingy", pb=self.state.vars.pendingbuys)
|
||||
##proto v pendingbuys pridano str(), protoze UUIN nejde serializovat
|
||||
##padalo na variable changed during iteration, pridano
|
||||
if len(self.state.vars.pendingbuys)>0:
|
||||
tmp = copy.deepcopy(self.state.vars.pendingbuys)
|
||||
for key in tmp:
|
||||
#ic(key)
|
||||
#nejprve vyhodime z pendingbuys
|
||||
self.state.vars.pendingbuys.pop(key, False)
|
||||
if key != -1:
|
||||
res = self.interface.cancel(key)
|
||||
self.state.ilog(e=f"Pendingy zrusen pro {key=}", orderid=str(key), res=str(res))
|
||||
print("CANCEL PENDING BUYS RETURN", res)
|
||||
self.state.vars.pendingbuys={}
|
||||
self.state.vars.jevylozeno = 0
|
||||
print("cancel pending buys end")
|
||||
self.state.ilog(e="Dokončeno zruseni vsech pb", pb=self.state.vars.pendingbuys)
|
||||
|
||||
#kopie funkci co jsou v next jen async, nejak vymyslet, aby byly jen jedny
|
||||
async def is_defensive_mode(self):
|
||||
akt_pozic = int(self.state.positions)
|
||||
max_pozic = int(self.state.vars.maxpozic)
|
||||
def_mode_from = safe_get(self.state.vars, "def_mode_from")
|
||||
if def_mode_from == None: def_mode_from = max_pozic/2
|
||||
if akt_pozic >= int(def_mode_from):
|
||||
self.state.ilog(e=f"DEFENSIVE MODE active {self.state.vars.def_mode_from=}", msg=self.state.positions)
|
||||
return True
|
||||
else:
|
||||
self.state.ilog(e=f"STANDARD MODE active {self.state.vars.def_mode_from=}", msg=self.state.positions)
|
||||
return False
|
||||
|
||||
async def get_limitka_price(self):
|
||||
def_profit = safe_get(self.state.vars, "def_profit")
|
||||
if def_profit == None: def_profit = self.state.vars.profit
|
||||
cena = float(self.state.avgp)
|
||||
if await self.is_defensive_mode():
|
||||
return price2dec(cena+get_tick(cena,float(def_profit)))
|
||||
else:
|
||||
return price2dec(cena+get_tick(cena,float(self.state.vars.profit)))
|
||||
Binary file not shown.
@ -131,10 +131,18 @@ class Strategy:
|
||||
"""SAVE record to respective STATE variables (bar or trades)
|
||||
ukládáme i index pro případné indikátory - pro zobrazení v grafu
|
||||
----- NO support for simultaneous rectypes in one queue """
|
||||
|
||||
#do pole indikatoru se zde vzdycky prida nova hodnota (0)
|
||||
#tzn. v NEXT dealame u indikatoru vzdy pouze UPDATE
|
||||
|
||||
def save_item_history(self,item):
|
||||
if self.rectype == RecordType.BAR:
|
||||
#jako cas indikatorů pridavame cas baru, jejich hodnoty se naplni v nextu
|
||||
#jako cas indikatorů pridavame cas baru a inicialni hodnoty vsech indikatoru
|
||||
self.state.indicators['time'].append(item['time'])
|
||||
for key in self.state.indicators:
|
||||
if key == 'time':
|
||||
continue
|
||||
self.state.indicators[key].append(0)
|
||||
self.append_bar(self.state.bars,item)
|
||||
elif self.rectype == RecordType.TRADE:
|
||||
pass
|
||||
@ -144,17 +152,22 @@ class Strategy:
|
||||
elif self.rectype == RecordType.CBAR:
|
||||
#novy vzdy pridame
|
||||
if self.nextnew:
|
||||
self.state.indicators['time'].append(item['time'])
|
||||
self.state.indicators['time'].append(item['updated'])
|
||||
for key in self.state.indicators:
|
||||
if key == 'time':
|
||||
continue
|
||||
self.state.indicators[key].append(0)
|
||||
|
||||
self.append_bar(self.state.bars,item)
|
||||
self.nextnew = 0
|
||||
#nasledujici updatneme, po potvrzeni, nasleduje novy bar
|
||||
else:
|
||||
if item['confirmed'] == 0:
|
||||
self.state.indicators['time'][-1]=item['time']
|
||||
self.state.indicators['time'][-1]=item['updated']
|
||||
self.replace_prev_bar(self.state.bars,item)
|
||||
#confirmed
|
||||
else:
|
||||
self.state.indicators['time'][-1]=item['time']
|
||||
self.state.indicators['time'][-1]=item['updated']
|
||||
self.replace_prev_bar(self.state.bars,item)
|
||||
self.nextnew = 1
|
||||
|
||||
@ -224,14 +237,15 @@ class Strategy:
|
||||
self.before_iteration()
|
||||
ted = datetime.fromtimestamp(self.state.time).astimezone(zoneNY)
|
||||
if is_open_rush(ted, self.open_rush) or is_close_rush(ted, self.close_rush):
|
||||
pass
|
||||
#self.state.ilog(e="Rush hour - skipping")
|
||||
#identifikatory jsou ulozeny vektorove, tzn. kdyz nejdeme dovnitr iterace(tak nepotrebujeme prazdny cas pro tuto iteraci)
|
||||
#hodnoty time a identifikatoru musi byt stejne
|
||||
#TBD pripdane predelat a dodelat pro CBARy az je budu pouzivat
|
||||
if self.rectype == RecordType.BAR:
|
||||
self.state.indicators['time'].pop()
|
||||
elif self.rectype == RecordType.CBAR:
|
||||
print("RUSH skipping NOT IMPLEMENTED for CBARs yet")
|
||||
# if self.rectype == RecordType.BAR:
|
||||
# self.state.indicators['time'].pop()
|
||||
# elif self.rectype == RecordType.CBAR:
|
||||
# print("RUSH skipping NOT IMPLEMENTED for CBARs yet")
|
||||
|
||||
else:
|
||||
self.next(item, self.state)
|
||||
|
||||
Binary file not shown.
@ -124,12 +124,12 @@ def print(*args, **kwargs):
|
||||
####ic(*args, **kwargs)
|
||||
richprint(*args, **kwargs)
|
||||
|
||||
def price2dec(price: float) -> float:
|
||||
def price2dec(price: float, decimals: int = 2) -> float:
|
||||
"""
|
||||
pousti maximalne 2 decimals
|
||||
pokud je trojmistne a vic pak zakrouhli na 2, jinak necha
|
||||
"""
|
||||
return round(price,2) if count_decimals(price) > 2 else price
|
||||
return round(price,decimals) if count_decimals(price) > decimals else price
|
||||
|
||||
def count_decimals(number: float) -> int:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user