refactor RSI SELL
This commit is contained in:
@ -5,7 +5,7 @@ from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import Strat
|
||||
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 v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, get_tick, round2five
|
||||
from datetime import datetime
|
||||
#from icecream import install, ic
|
||||
#from rich import print
|
||||
@ -175,6 +175,10 @@ def next(data, state: StrategyState):
|
||||
akt_pozic = int(state.positions)
|
||||
max_pozic = int(state.vars.maxpozic)
|
||||
|
||||
if akt_pozic >= max_pozic:
|
||||
state.ilog(e="MAX pozic reached, cannot vyklad")
|
||||
return
|
||||
|
||||
#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)
|
||||
@ -243,31 +247,38 @@ def next(data, state: StrategyState):
|
||||
|
||||
#na urovni CBARU mame zajisteno, ze update prichazi pri zmene ceny
|
||||
#v kazde iteraci testujeme sell
|
||||
#pri confirmed tesutjeme i buy
|
||||
#pri potvrzenem baru muzeme provest kroky per hlavni BAR
|
||||
#potvrzeni neprinasi nikdy zadna nova data, ale pouze potvrzeni.
|
||||
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:
|
||||
if conf_bar == 1:
|
||||
#delej veci per standardni bar
|
||||
state.ilog(e="BAR potvrzeny")
|
||||
else:
|
||||
pass
|
||||
#delej veci tick-based
|
||||
|
||||
##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
|
||||
#CBAR INDICATOR pro tick price a deltu VOLUME
|
||||
tick_price = round2five(data['close'])
|
||||
tick_delta_volume = data['volume'] - state.vars.last_tick_volume
|
||||
|
||||
if conf_bar == 0:
|
||||
try:
|
||||
#pokud v potvrzovacím baru nebyly zmeny, nechavam puvodni hodnoty
|
||||
# if tick_delta_volume == 0:
|
||||
# state.indicators.tick_price[-1] = state.indicators.tick_price[-2]
|
||||
# state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2]
|
||||
# else:
|
||||
|
||||
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)
|
||||
#docasne dame pryc volume deltu a davame absolutni cislo
|
||||
state.cbar_indicators.tick_price[-1] = tick_price
|
||||
state.cbar_indicators.tick_volume[-1] = tick_delta_volume
|
||||
except:
|
||||
pass
|
||||
|
||||
state.ilog(e=f"TICK PRICE {tick_price} VOLUME {tick_delta_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']
|
||||
@ -278,6 +289,18 @@ def next(data, state: StrategyState):
|
||||
|
||||
|
||||
|
||||
#TEST BUY SIGNALu z cbartick_price - 3klesave za sebou
|
||||
buy_tp = isfalling(state.cbar_indicators.tick_price,state.vars.Trend)
|
||||
state.ilog(e=f"TICK SIGNAL ISFALLING {buy_tp}", last_tp=state.cbar_indicators.tick_price[-6:], trend=state.vars.Trend)
|
||||
|
||||
#IVWAP - PRUBEZNY persistovany VWAP
|
||||
# try:
|
||||
# #naplneni cbar tick indikatoru s prubeznou vwap
|
||||
# state.cbar_indicators.ivwap[-1]=data['vwap']
|
||||
# except:
|
||||
# pass
|
||||
|
||||
|
||||
# if data['confirmed'] == 0:
|
||||
# state.ilog(e="CBAR unconfirmed - returned", msg=str(data))
|
||||
# #TBD zde muzeme i nakupovat
|
||||
@ -287,7 +310,7 @@ def next(data, state: StrategyState):
|
||||
# else:
|
||||
# state.ilog(e="CBAR confirmed - continue", msg=str(data))
|
||||
|
||||
#EMA INDICATOR -
|
||||
#BAR EMA INDICATOR -
|
||||
#plnime MAcko - nyni posilame jen N poslednich hodnot
|
||||
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
|
||||
try:
|
||||
@ -296,27 +319,31 @@ def next(data, state: StrategyState):
|
||||
source = state.bars.close[-ma:] #state.bars.vwap
|
||||
ema_value = ema(source, ma)
|
||||
state.indicators.ema[-1]=trunc(ema_value[-1],3)
|
||||
state.ilog(e=f"EMA {state.indicators.ema[-1]}", ema_last=state.indicators.ema[-6:])
|
||||
except Exception as e:
|
||||
state.ilog(e="EMA nechavame 0", message=str(e)+format_exc())
|
||||
#state.indicators.ema[-1]=(0)
|
||||
|
||||
#RSI14 INDICATOR
|
||||
#CBAR 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_length = 14
|
||||
|
||||
#source = state.bars.close #[-rsi_length:] #state.bars.vwap
|
||||
#jako zdroj je prubezna CBAR tickprice
|
||||
source = state.cbar_indicators.tick_price
|
||||
rsi_res = rsi(source, rsi_length)
|
||||
rsi_value = trunc(rsi_res[-1],3)
|
||||
state.indicators.RSI14[-1]=rsi_value
|
||||
state.cbar_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:])
|
||||
state.ilog(e=f"CBARRSI{rsi_value} {rsi_length=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.cbar_indicators.RSI14[-5:])
|
||||
except Exception as e:
|
||||
state.ilog(e=f"RSI {rsi_length=} nechavame 0", message=str(e)+format_exc())
|
||||
state.ilog(e=f"CBARRSI {rsi_length=} nechavame 0", message=str(e)+format_exc())
|
||||
#state.indicators.RSI14.append(0)
|
||||
|
||||
|
||||
@ -417,9 +444,8 @@ def next(data, state: StrategyState):
|
||||
#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:
|
||||
if state.vars.jevylozeno == 1 and len(state.vars.pendingbuys)>0:
|
||||
#pokud mame vylozeno a cena je vetsi nez tick2reset
|
||||
if len(state.vars.pendingbuys)>0:
|
||||
maxprice = max(state.vars.pendingbuys.values())
|
||||
@ -443,34 +469,6 @@ def next(data, state: StrategyState):
|
||||
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):
|
||||
@ -481,12 +479,13 @@ def init(state: StrategyState):
|
||||
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.cbar_indicators['ivwap'] = []
|
||||
state.cbar_indicators['tick_price'] = []
|
||||
state.cbar_indicators['tick_volume'] = []
|
||||
state.indicators['ema'] = []
|
||||
state.indicators['slope'] = []
|
||||
state.indicators['slopeMA'] = []
|
||||
state.indicators['RSI14'] = []
|
||||
state.cbar_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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -194,7 +194,7 @@ class RunArchiveDetail(BaseModel):
|
||||
name: str
|
||||
bars: dict
|
||||
#trades: Optional[dict]
|
||||
indicators: dict
|
||||
indicators: List[dict]
|
||||
statinds: dict
|
||||
trades: List[TradeUpdate]
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ from appdirs import user_data_dir
|
||||
NORMALIZED_TICK_BASE_PRICE = 30.00
|
||||
LOG_RUNNER_EVENTS = False
|
||||
#no print in console
|
||||
QUIET_MODE = True
|
||||
QUIET_MODE = False
|
||||
#how many consecutive trades with the fill price are necessary for LIMIT fill to happen in backtesting
|
||||
#0 - optimistic, every knot high will fill the order
|
||||
#N - N consecutive trades required
|
||||
|
||||
@ -458,6 +458,8 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
|
||||
|
||||
#flatten indicators from numpy array
|
||||
flattened_indicators = {}
|
||||
#pole indicatoru, kazdy ma svoji casovou osu time
|
||||
flattened_indicators_list = []
|
||||
for key, value in strat.state.indicators.items():
|
||||
if isinstance(value, ndarray):
|
||||
#print("is numpy", key,value)
|
||||
@ -466,11 +468,22 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
|
||||
else:
|
||||
#print("is not numpy", key, value)
|
||||
flattened_indicators[key]= value
|
||||
flattened_indicators_list.append(flattened_indicators)
|
||||
flattened_indicators = {}
|
||||
for key, value in strat.state.cbar_indicators.items():
|
||||
if isinstance(value, ndarray):
|
||||
#print("is numpy", key,value)
|
||||
flattened_indicators[key]= value.tolist()
|
||||
#print("changed numpy:",value.tolist())
|
||||
else:
|
||||
#print("is not numpy", key, value)
|
||||
flattened_indicators[key]= value
|
||||
flattened_indicators_list.append(flattened_indicators)
|
||||
|
||||
runArchiveDetail: RunArchiveDetail = RunArchiveDetail(id = runner.id,
|
||||
name=runner.run_name,
|
||||
bars=strat.state.bars,
|
||||
indicators=flattened_indicators,
|
||||
indicators=flattened_indicators_list,
|
||||
statinds=strat.state.statinds,
|
||||
trades=strat.state.tradeList)
|
||||
resh = db_arch_h.insert(runArchive.__dict__)
|
||||
|
||||
Binary file not shown.
@ -23,6 +23,8 @@ class TradeAggregator:
|
||||
mintick: int = 0,
|
||||
exthours: bool = False):
|
||||
"""
|
||||
UPDATED VERSION - vrací více záznamů
|
||||
|
||||
Create trade agregator. Instance accepts trades one by one and process them and returns output type
|
||||
Trade - return trade one by one (no change)
|
||||
Bar - return finished bar in given timeframe
|
||||
@ -62,6 +64,8 @@ class TradeAggregator:
|
||||
#instance variable to hold last trade price
|
||||
self.last_price = 0
|
||||
self.barindex = 1
|
||||
self.diff_price = True
|
||||
self.preconfBar = {}
|
||||
|
||||
async def ingest_trade(self, indata, symbol):
|
||||
"""
|
||||
@ -72,7 +76,7 @@ class TradeAggregator:
|
||||
data = unpackb(indata)
|
||||
|
||||
#last item signal
|
||||
if data == "last": return data
|
||||
if data == "last": return [data]
|
||||
|
||||
#print(data)
|
||||
##implementing fitlers - zatim natvrdo a jen tyto: size: 1, cond in [O,C,4] opening,closed a derivately priced,
|
||||
@ -82,15 +86,15 @@ class TradeAggregator:
|
||||
## 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','W','U'): return 0
|
||||
if i in ('C','O','4','B','7','V','P','W','U'): return []
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
#EXPERIMENT zkusime vyhodit vsechny pod 50 #puv if int(data['s']) == 1: return 0
|
||||
#EXPERIMENT zkusime vyhodit vsechny pod 50 #puv if int(data['s']) == 1: return []
|
||||
#zatim nechavame - výsledek je naprosto stejný jako v tradingview
|
||||
if int(data['s']) < self.minsize: return 0
|
||||
if int(data['s']) < self.minsize: return []
|
||||
#{'t': 1678982075.242897, 'x': 'D', 'p': 29.1333, 's': 18000, 'c': [' ', '7', 'V'], 'i': 79372107591749, 'z': 'A', 'u': 'incorrect'}
|
||||
if 'u' in data: return 0
|
||||
if 'u' in data: return []
|
||||
|
||||
#pokud projde TRADE s cenou 0.33% rozdilna oproti predchozi, pak vyhazujeme v ramci cisteni dat (cca 10ticku na 30USD)
|
||||
pct_off = 0.33
|
||||
@ -106,7 +110,7 @@ class TradeAggregator:
|
||||
if float(data['p']) > float(ltp.price[symbol]) + (float(data['p'])/100*pct_off) or float(data['p']) < float(ltp.price[symbol])-(float(data['p'])/100*pct_off):
|
||||
print("ZLO", data,ltp.price[symbol])
|
||||
#nechavame zlo zatim projit
|
||||
##return 0
|
||||
##return []
|
||||
# with open("cache/wrongtrades.txt", 'a') as fp:
|
||||
# fp.write(str(data) + 'predchozi:'+str(ltp.price[symbol])+'\n')
|
||||
|
||||
@ -128,7 +132,7 @@ class TradeAggregator:
|
||||
|
||||
if not is_open_hours(datetime.fromtimestamp(data['t'])) and self.exthours is False:
|
||||
#print("AGG: trade not in open hours skipping", datetime.fromtimestamp(data['t']).astimezone(zoneNY))
|
||||
return 0
|
||||
return []
|
||||
|
||||
#tady bude vzdycky posledni cena a posledni cas
|
||||
if self.update_ltp:
|
||||
@ -137,7 +141,7 @@ class TradeAggregator:
|
||||
|
||||
#if data['p'] < self.last_price - 0.02: print("zlo:",data)
|
||||
|
||||
if self.rectype == RecordType.TRADE: return data
|
||||
if self.rectype == RecordType.TRADE: return [data]
|
||||
|
||||
#print("agr přišel trade", datetime.fromtimestamp(data['t']),data)
|
||||
|
||||
@ -167,9 +171,45 @@ class TradeAggregator:
|
||||
else:
|
||||
self.newBar['confirmed'] = 1
|
||||
self.newBar['vwap'] = self.vwaphelper / self.newBar['volume']
|
||||
#updatujeme čas - obsahuje datum tradu, který confirm triggeroval
|
||||
self.newBar['updated'] = data['t']
|
||||
|
||||
|
||||
#HACK pro update casu, který confirm triggeroval
|
||||
#u CBARu v confirmnutem muze byt
|
||||
# 1) no trades (pak potvrzujeme predchozi)
|
||||
# 2) trades with same price , ktere zaroven timto flushujeme (v tomto pripade je cas updatu cas predchoziho tradu)
|
||||
|
||||
# variantu vyse pozname podle nastavene self.diff_price = True (mame trady a i ulozeny cas)
|
||||
if self.rectype == RecordType.CBAR:
|
||||
#UPDATE ať confirmace nenese zadna data, vsechny zmenena data jsou vyflusnute predtim
|
||||
#pokud byly nejake trady
|
||||
if self.diff_price is False:
|
||||
#self.newBar['updated'] = self.lasttimestamp
|
||||
|
||||
#TODO tady bychom nejdriv vyflushnuly nekonfirmovany bar s trady
|
||||
#a nasladne poslali prazdny confirmacni bar
|
||||
self.preconfBar = deepcopy(self.newBar)
|
||||
self.preconfBar['updated'] = self.lasttimestamp
|
||||
self.preconfBar['confirmed'] = 0
|
||||
#pridat do promenne
|
||||
|
||||
#else:
|
||||
#NASTY HACK pro GUI
|
||||
#zkousime potvrzeni baru dat o chlup mensi cas nez cas noveho baru, ktery jde hned za nim
|
||||
#gui neumi zobrazit duplicity a v RT grafu nejde upravovat zpetne
|
||||
#zarovname na cas baru podle timeframu(např. 5, 10, 15 ...) (ROUND)
|
||||
if self.align:
|
||||
t = datetime.fromtimestamp(data['t'])
|
||||
t = t - timedelta(seconds=t.second % self.timeframe,microseconds=t.microsecond)
|
||||
#nebo pouzijeme datum tradu zaokrouhlene na vteriny (RANDOM)
|
||||
else:
|
||||
#ulozime si jeho timestamp (odtum pocitame timeframe)
|
||||
t = datetime.fromtimestamp(int(data['t']))
|
||||
|
||||
#self.newBar['updated'] = float(data['t']) - 0.001
|
||||
self.newBar['updated'] = datetime.timestamp(t) - 0.000001
|
||||
#PRO standardní BAR nechavame puvodni
|
||||
else:
|
||||
self.newBar['updated'] = data['t']
|
||||
#ulozime datum akt.tradu pro mintick
|
||||
self.lastBarConfirmed = True
|
||||
#ukládám si předchozí (confirmed)bar k vrácení
|
||||
@ -199,9 +239,9 @@ class TradeAggregator:
|
||||
|
||||
#je cena stejna od predchoziho tradu? pro nepotvrzeny cbar vracime jen pri zmene ceny
|
||||
if self.last_price == data['p']:
|
||||
diff_price = False
|
||||
self.diff_price = False
|
||||
else:
|
||||
diff_price = True
|
||||
self.diff_price = True
|
||||
self.last_price = data['p']
|
||||
|
||||
#spočteme vwap - potřebujeme předchozí hodnoty
|
||||
@ -216,6 +256,7 @@ class TradeAggregator:
|
||||
self.newBar['hlcc4'] = round((self.newBar['high']+self.newBar['low']+self.newBar['close']+self.newBar['close'])/4,3)
|
||||
|
||||
#predchozi bar byl v jine vterine, tzn. ukladame do noveho (aktualniho) pocatecni hodnoty
|
||||
#NEW BAR POPULATION
|
||||
if (issamebar == False):
|
||||
#zaciname novy bar
|
||||
|
||||
@ -249,14 +290,30 @@ class TradeAggregator:
|
||||
#je tu maly bug pro CBAR - kdy prvni trade, který potvrzuje predchozi bar
|
||||
#odesle potvrzeni predchoziho baru a nikoliv open stávajícího, ten posle až druhý trade
|
||||
#což asi nevadí
|
||||
#OPRAVENO
|
||||
|
||||
|
||||
#pokud je pripraveny, vracíme předchozí confirmed bar
|
||||
#pokud je pripraveny, vracíme předchozí confirmed bar PLUS NOVY, který ho triggeroval. pokud bylo
|
||||
# pred confirmem nejake trady beze zmeny ceny flushujeme je take (preconfBar)
|
||||
#predchozi bar muze obsahovat zmenena data
|
||||
if len(self.returnBar) > 0:
|
||||
self.tmp = self.returnBar
|
||||
self.returnBar = {}
|
||||
#print(self.tmp)
|
||||
return self.tmp
|
||||
return_set = []
|
||||
#pridame preconfirm bar pokud je
|
||||
if len(self.preconfBar)>0:
|
||||
return_set.append(self.preconfBar)
|
||||
self.preconfBar = {}
|
||||
#pridame confirmation bar
|
||||
return_set.append(self.returnBar)
|
||||
#self.tmp = self.returnBar
|
||||
self.returnBar = []
|
||||
#doplnime prubezny vwap
|
||||
self.newBar['vwap'] = self.vwaphelper / self.newBar['volume']
|
||||
return_set.append(self.newBar)
|
||||
#TODO pridat sem podporu pro mintick jako nize, tzn. pokud je v ochrannem okne, tak novy bar nevracet
|
||||
#zatim je novy bar odesilan nehlede na mintick
|
||||
#return_set = [self.tmp, self.newBar]
|
||||
|
||||
return return_set
|
||||
|
||||
#pro cont bar posilame ihned (TBD vwap a min bar tick value)
|
||||
if self.rectype == RecordType.CBAR:
|
||||
@ -267,7 +324,7 @@ class TradeAggregator:
|
||||
#pocatek noveho baru + Xs musi byt vetsi nez aktualni trade
|
||||
if (self.newBar['time'] + timedelta(seconds=self.mintick)) > datetime.fromtimestamp(data['t']):
|
||||
#print("waiting for mintick")
|
||||
return 0
|
||||
return []
|
||||
else:
|
||||
self.lastBarConfirmed = False
|
||||
|
||||
@ -276,12 +333,12 @@ class TradeAggregator:
|
||||
#print(self.newBar)
|
||||
|
||||
#pro (nepotvrzeny) cbar vracime jen pri zmene ceny
|
||||
if diff_price is True:
|
||||
return self.newBar
|
||||
if self.diff_price is True:
|
||||
return [self.newBar]
|
||||
else:
|
||||
return 0
|
||||
return []
|
||||
else:
|
||||
return 0
|
||||
return []
|
||||
|
||||
|
||||
class TradeAggregator2Queue(TradeAggregator):
|
||||
@ -297,15 +354,17 @@ class TradeAggregator2Queue(TradeAggregator):
|
||||
async def ingest_trade(self, data):
|
||||
#print("ingest ve threadu:",current_thread().name)
|
||||
res = await super().ingest_trade(data, self.symbol)
|
||||
if res != 0:
|
||||
|
||||
#if len(res) > 0:
|
||||
for obj in res:
|
||||
#print(res)
|
||||
#pri rychlem plneni vetsiho dictionary se prepisovali - vyreseno kopií
|
||||
if isinstance(res, dict):
|
||||
copy = res.copy()
|
||||
if isinstance(obj, dict):
|
||||
copy = obj.copy()
|
||||
else:
|
||||
copy = res
|
||||
copy = obj
|
||||
self.queue.put(copy)
|
||||
res = {}
|
||||
res = []
|
||||
#print("po insertu",res)
|
||||
|
||||
class TradeAggregator2List(TradeAggregator):
|
||||
@ -324,17 +383,17 @@ class TradeAggregator2List(TradeAggregator):
|
||||
#print("ted vstoupil do tradeagg2list ingestu")
|
||||
res1 = await super().ingest_trade(data, self.symbol)
|
||||
#print("ted je po zpracovani", res1)
|
||||
if res1 != 0:
|
||||
for obj in res1:
|
||||
#pri rychlem plneni vetsiho dictionary se prepisovali - vyreseno kopií
|
||||
if isinstance(res1, dict):
|
||||
copy = res1.copy()
|
||||
if isinstance(obj, dict):
|
||||
copy = obj.copy()
|
||||
else:
|
||||
copy = res1
|
||||
if res1 == 'last': return 0
|
||||
copy = obj
|
||||
if obj == 'last': return []
|
||||
self.btdata.append((copy['t'],copy['p']))
|
||||
# with open(self.debugfile, "a") as output:
|
||||
# output.write(str(copy['t']) + ' ' + str(datetime.fromtimestamp(copy['t']).astimezone(zoneNY)) + ' ' + str(copy['p']) + '\n')
|
||||
res1 = {}
|
||||
res1 = []
|
||||
#print("po insertu",res)
|
||||
|
||||
|
||||
|
||||
341
v2realbot/loader/aggregator_old.py
Normal file
341
v2realbot/loader/aggregator_old.py
Normal file
@ -0,0 +1,341 @@
|
||||
"""
|
||||
Aggregator mdoule containing main aggregator logic for TRADES, BARS and CBAR
|
||||
"""
|
||||
from v2realbot.enums.enums import RecordType, StartBarAlign
|
||||
from datetime import datetime, timedelta
|
||||
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, Queue,is_open_hours,zoneNY
|
||||
from queue import Queue
|
||||
from rich import print
|
||||
from v2realbot.enums.enums import Mode
|
||||
import threading
|
||||
from copy import deepcopy
|
||||
from msgpack import unpackb
|
||||
import os
|
||||
from config import DATA_DIR
|
||||
|
||||
class TradeAggregator:
|
||||
def __init__(self,
|
||||
rectype: RecordType = RecordType.BAR,
|
||||
timeframe: int = 5,
|
||||
minsize: int = 100,
|
||||
update_ltp: bool = False,
|
||||
align: StartBarAlign = StartBarAlign.ROUND,
|
||||
mintick: int = 0,
|
||||
exthours: bool = False):
|
||||
"""
|
||||
Create trade agregator. Instance accepts trades one by one and process them and returns output type
|
||||
Trade - return trade one by one (no change)
|
||||
Bar - return finished bar in given timeframe
|
||||
CBar - returns continuous bar, finished bar is marked by confirmed status
|
||||
Args:
|
||||
timeframe (number): Resolution of bar in seconds
|
||||
update_ltp (bool): Whether to update global variable with price (usually only one instance does that)
|
||||
align: Defines alignement of first bar. ROUND - according to timeframe( 5,10,15 - for 5s timeframe), RANDOM - according to timestamp of first trade
|
||||
mintick: Applies for CBAR. Minimální mezera po potvrzeni baru a aktualizaci dalsiho nepotvrzeneho (např. pro 15s, muzeme chtit prvni tick po 5s). po teto dobe realtime.
|
||||
"""
|
||||
self.rectype: RecordType = rectype
|
||||
self.timeframe = timeframe
|
||||
self.minsize = minsize
|
||||
self.update_ltp = update_ltp
|
||||
self.exthours = exthours
|
||||
|
||||
if mintick >= timeframe:
|
||||
print("Mintick musi byt mensi nez timeframe")
|
||||
raise Exception
|
||||
|
||||
self.mintick = mintick
|
||||
#class variables = starters
|
||||
self.iterace = 1
|
||||
self.lasttimestamp = 0
|
||||
#inicalizace pro prvni agregaci
|
||||
self.newBar = dict(high=0, low=999999, volume = 0, trades = 0, confirmed = 0, vwap = 0, close=0, index = 1, updated = 0)
|
||||
self.bar_start = 0
|
||||
self.align = align
|
||||
self.tm: datetime = None
|
||||
self.firstpass = True
|
||||
self.vwaphelper = 0
|
||||
self.returnBar = {}
|
||||
self.lastBarConfirmed = False
|
||||
#min trade size
|
||||
self.minsize = minsize
|
||||
|
||||
#instance variable to hold last trade price
|
||||
self.last_price = 0
|
||||
self.barindex = 1
|
||||
|
||||
async def ingest_trade(self, indata, symbol):
|
||||
"""
|
||||
Aggregator logic for trade record
|
||||
Args:
|
||||
indata (dict): online or offline record
|
||||
"""
|
||||
data = unpackb(indata)
|
||||
|
||||
#last item signal
|
||||
if data == "last": return data
|
||||
|
||||
#print(data)
|
||||
##implementing fitlers - zatim natvrdo a jen tyto: size: 1, cond in [O,C,4] opening,closed a derivately priced,
|
||||
## 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','W','U'): return 0
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
#EXPERIMENT zkusime vyhodit vsechny pod 50 #puv if int(data['s']) == 1: return 0
|
||||
#zatim nechavame - výsledek je naprosto stejný jako v tradingview
|
||||
if int(data['s']) < self.minsize: return 0
|
||||
#{'t': 1678982075.242897, 'x': 'D', 'p': 29.1333, 's': 18000, 'c': [' ', '7', 'V'], 'i': 79372107591749, 'z': 'A', 'u': 'incorrect'}
|
||||
if 'u' in data: return 0
|
||||
|
||||
#pokud projde TRADE s cenou 0.33% rozdilna oproti predchozi, pak vyhazujeme v ramci cisteni dat (cca 10ticku na 30USD)
|
||||
pct_off = 0.33
|
||||
##ic(ltp.price)
|
||||
##ic(ltp.price[symbol])
|
||||
|
||||
try:
|
||||
ltp.price[symbol]
|
||||
except KeyError:
|
||||
ltp.price[symbol]=data['p']
|
||||
|
||||
|
||||
if float(data['p']) > float(ltp.price[symbol]) + (float(data['p'])/100*pct_off) or float(data['p']) < float(ltp.price[symbol])-(float(data['p'])/100*pct_off):
|
||||
print("ZLO", data,ltp.price[symbol])
|
||||
#nechavame zlo zatim projit
|
||||
##return 0
|
||||
# with open("cache/wrongtrades.txt", 'a') as fp:
|
||||
# fp.write(str(data) + 'predchozi:'+str(ltp.price[symbol])+'\n')
|
||||
|
||||
#timestampy jsou v UTC
|
||||
#TIMESTAMP format is different for online and offline trade streams
|
||||
#offline trade
|
||||
#{'t': '2023-02-17T14:30:00.16111744Z', 'x': 'J', 'p': 35.14, 's': 20, 'c': [' ', 'F', 'I'], 'i': 52983525027938, 'z': 'A'}
|
||||
#websocket trade
|
||||
#{'T': 't', 'S': 'MSFT', 'i': 372, 'x': 'V', 'p': 264.58, 's': 25, 'c': ['@', 'I'], 'z': 'C', 't': Timestamp(seconds=1678973696, nanoseconds=67312449), 'r': Timestamp(seconds=1678973696, nanoseconds=72865209)}
|
||||
#parse alpaca timestamp
|
||||
|
||||
# tzn. na offline mohu pouzit >>> datetime.fromisoformat(d).timestamp() 1676644200.161117
|
||||
#orizne sice nanosekundy ale to nevadi
|
||||
#print("tady", self.mode, data['t'])
|
||||
# if self.mode == Mode.BT:
|
||||
# data['t'] = datetime.fromisoformat(str(data['t'])).timestamp()
|
||||
# else:
|
||||
data['t'] = parse_alpaca_timestamp(data['t'])
|
||||
|
||||
if not is_open_hours(datetime.fromtimestamp(data['t'])) and self.exthours is False:
|
||||
#print("AGG: trade not in open hours skipping", datetime.fromtimestamp(data['t']).astimezone(zoneNY))
|
||||
return 0
|
||||
|
||||
#tady bude vzdycky posledni cena a posledni cas
|
||||
if self.update_ltp:
|
||||
ltp.price[symbol] = data['p']
|
||||
ltp.time[symbol] = data['t']
|
||||
|
||||
#if data['p'] < self.last_price - 0.02: print("zlo:",data)
|
||||
|
||||
if self.rectype == RecordType.TRADE: return data
|
||||
|
||||
#print("agr přišel trade", datetime.fromtimestamp(data['t']),data)
|
||||
|
||||
#OPIC pokud bude vadit, ze prvni bar neni kompletni - pak zapnout tuto opicarnu
|
||||
#kddyz jde o prvni iteraci a pozadujeme align, cekame na kulaty cas (pro 5s 0,5,10..)
|
||||
# if self.lasttimestamp ==0 and self.align:
|
||||
# if self.firstpass:
|
||||
# self.tm = datetime.fromtimestamp(data['t'])
|
||||
# self.tm += timedelta(seconds=self.timeframe)
|
||||
# self.tm = self.tm - timedelta(seconds=self.tm.second % self.timeframe,microseconds=self.tm.microsecond)
|
||||
# self.firstpass = False
|
||||
# print("trade: ",datetime.fromtimestamp(data['t']))
|
||||
# print("required",self.tm)
|
||||
# if self.tm > datetime.fromtimestamp(data['t']):
|
||||
# return
|
||||
# else: pass
|
||||
|
||||
#print("barstart",datetime.fromtimestamp(self.bar_start))
|
||||
#print("oriznute data z tradu", datetime.fromtimestamp(int(data['t'])))
|
||||
#print("timeframe",self.timeframe)
|
||||
if int(data['t']) - self.bar_start < self.timeframe:
|
||||
issamebar = True
|
||||
else:
|
||||
issamebar = False
|
||||
##flush předchozí bar a incializace (krom prvni iterace)
|
||||
if self.lasttimestamp ==0: pass
|
||||
else:
|
||||
self.newBar['confirmed'] = 1
|
||||
self.newBar['vwap'] = self.vwaphelper / self.newBar['volume']
|
||||
#updatujeme čas - obsahuje datum tradu, který confirm triggeroval
|
||||
self.newBar['updated'] = data['t']
|
||||
|
||||
#ulozime datum akt.tradu pro mintick
|
||||
self.lastBarConfirmed = True
|
||||
#ukládám si předchozí (confirmed)bar k vrácení
|
||||
self.returnBar = self.newBar
|
||||
#print(self.returnBar)
|
||||
|
||||
#inicializuji pro nový bar
|
||||
self.vwaphelper = 0
|
||||
|
||||
# return self.newBar
|
||||
##flush CONFIRMED bar to queue
|
||||
#self.q.put(self.newBar)
|
||||
##TODO pridat prubezne odesilani pokud je pozadovano
|
||||
self.barindex +=1
|
||||
self.newBar = {
|
||||
"close": 0,
|
||||
"high": 0,
|
||||
"low": 99999999,
|
||||
"volume": 0,
|
||||
"trades": 0,
|
||||
"hlcc4": 0,
|
||||
"confirmed": 0,
|
||||
"updated": 0,
|
||||
"vwap": 0,
|
||||
"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
|
||||
self.vwaphelper += (data['p'] * data['s'])
|
||||
self.newBar['updated'] = data['t']
|
||||
self.newBar['close'] = data['p']
|
||||
self.newBar['high'] = max(self.newBar['high'],data['p'])
|
||||
self.newBar['low'] = min(self.newBar['low'],data['p'])
|
||||
self.newBar['volume'] = self.newBar['volume'] + data['s']
|
||||
self.newBar['trades'] = self.newBar['trades'] + 1
|
||||
#pohrat si s timto round
|
||||
self.newBar['hlcc4'] = round((self.newBar['high']+self.newBar['low']+self.newBar['close']+self.newBar['close'])/4,3)
|
||||
|
||||
#predchozi bar byl v jine vterine, tzn. ukladame do noveho (aktualniho) pocatecni hodnoty
|
||||
if (issamebar == False):
|
||||
#zaciname novy bar
|
||||
|
||||
self.newBar['open'] = data['p']
|
||||
|
||||
#zarovname time prvniho baru podle timeframu kam patří (např. 5, 10, 15 ...) (ROUND)
|
||||
if self.align:
|
||||
t = datetime.fromtimestamp(data['t'])
|
||||
t = t - timedelta(seconds=t.second % self.timeframe,microseconds=t.microsecond)
|
||||
self.bar_start = datetime.timestamp(t)
|
||||
#nebo pouzijeme datum tradu zaokrouhlene na vteriny (RANDOM)
|
||||
else:
|
||||
#ulozime si jeho timestamp (odtum pocitame timeframe)
|
||||
t = datetime.fromtimestamp(int(data['t']))
|
||||
#timestamp
|
||||
self.bar_start = int(data['t'])
|
||||
|
||||
|
||||
|
||||
|
||||
self.newBar['time'] = t
|
||||
self.newBar['resolution'] = self.timeframe
|
||||
self.newBar['confirmed'] = 0
|
||||
|
||||
|
||||
#uložíme do předchozí hodnoty (poznáme tak open a close)
|
||||
self.lasttimestamp = data['t']
|
||||
self.iterace += 1
|
||||
# print(self.iterace, data)
|
||||
|
||||
#je tu maly bug pro CBAR - kdy prvni trade, který potvrzuje predchozi bar
|
||||
#odesle potvrzeni predchoziho baru a nikoliv open stávajícího, ten posle až druhý trade
|
||||
#což asi nevadí
|
||||
|
||||
|
||||
#pokud je pripraveny, vracíme předchozí confirmed bar
|
||||
if len(self.returnBar) > 0:
|
||||
self.tmp = self.returnBar
|
||||
self.returnBar = {}
|
||||
#print(self.tmp)
|
||||
return self.tmp
|
||||
|
||||
#pro cont bar posilame ihned (TBD vwap a min bar tick value)
|
||||
if self.rectype == RecordType.CBAR:
|
||||
|
||||
#pokud je mintick nastavený a předchozí bar byl potvrzený
|
||||
if self.mintick != 0 and self.lastBarConfirmed:
|
||||
#d zacatku noveho baru musi ubehnout x sekund nez posilame updazte
|
||||
#pocatek noveho baru + Xs musi byt vetsi nez aktualni trade
|
||||
if (self.newBar['time'] + timedelta(seconds=self.mintick)) > datetime.fromtimestamp(data['t']):
|
||||
#print("waiting for mintick")
|
||||
return 0
|
||||
else:
|
||||
self.lastBarConfirmed = False
|
||||
|
||||
#doplnime prubezny vwap
|
||||
self.newBar['vwap'] = self.vwaphelper / self.newBar['volume']
|
||||
#print(self.newBar)
|
||||
|
||||
#pro (nepotvrzeny) cbar vracime jen pri zmene ceny
|
||||
if diff_price is True:
|
||||
return self.newBar
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
class TradeAggregator2Queue(TradeAggregator):
|
||||
"""
|
||||
Child of TradeAggregator - sends items to given queue
|
||||
In the future others will be added - TradeAggToTxT etc.
|
||||
"""
|
||||
def __init__(self, symbol: str, queue: Queue, rectype: RecordType = RecordType.BAR, timeframe: int = 5, minsize: int = 100, update_ltp: bool = False, align: StartBarAlign = StartBarAlign.ROUND, mintick: int = 0, exthours: bool = False):
|
||||
super().__init__(rectype=rectype, timeframe=timeframe, minsize=minsize, update_ltp=update_ltp, align=align, mintick=mintick, exthours=exthours)
|
||||
self.queue = queue
|
||||
self.symbol = symbol
|
||||
|
||||
async def ingest_trade(self, data):
|
||||
#print("ingest ve threadu:",current_thread().name)
|
||||
res = await super().ingest_trade(data, self.symbol)
|
||||
if res != 0:
|
||||
#print(res)
|
||||
#pri rychlem plneni vetsiho dictionary se prepisovali - vyreseno kopií
|
||||
if isinstance(res, dict):
|
||||
copy = res.copy()
|
||||
else:
|
||||
copy = res
|
||||
self.queue.put(copy)
|
||||
res = {}
|
||||
#print("po insertu",res)
|
||||
|
||||
class TradeAggregator2List(TradeAggregator):
|
||||
""""
|
||||
stores records to the list
|
||||
"""
|
||||
def __init__(self, symbol: str, btdata: list, rectype: RecordType = RecordType.BAR, timeframe: int = 5, minsize: int = 100, update_ltp: bool = False, align: StartBarAlign = StartBarAlign.ROUND, mintick: int = 0, exthours: bool = False):
|
||||
super().__init__(rectype=rectype, timeframe=timeframe, minsize=minsize, update_ltp=update_ltp, align=align, mintick=mintick, exthours=exthours)
|
||||
self.btdata = btdata
|
||||
self.symbol = symbol
|
||||
# self.debugfile = DATA_DIR + "/BACprices.txt"
|
||||
# if os.path.exists(self.debugfile):
|
||||
# os.remove(self.debugfile)
|
||||
|
||||
async def ingest_trade(self, data):
|
||||
#print("ted vstoupil do tradeagg2list ingestu")
|
||||
res1 = await super().ingest_trade(data, self.symbol)
|
||||
#print("ted je po zpracovani", res1)
|
||||
if res1 != 0:
|
||||
#pri rychlem plneni vetsiho dictionary se prepisovali - vyreseno kopií
|
||||
if isinstance(res1, dict):
|
||||
copy = res1.copy()
|
||||
else:
|
||||
copy = res1
|
||||
if res1 == 'last': return 0
|
||||
self.btdata.append((copy['t'],copy['p']))
|
||||
# with open(self.debugfile, "a") as output:
|
||||
# output.write(str(copy['t']) + ' ' + str(datetime.fromtimestamp(copy['t']).astimezone(zoneNY)) + ' ' + str(copy['p']) + '\n')
|
||||
res1 = {}
|
||||
#print("po insertu",res)
|
||||
|
||||
|
||||
|
||||
@ -127,8 +127,6 @@ function transform_data(data) {
|
||||
|
||||
//pro jistotu jeste seradime podle casu
|
||||
//v BT se muze predbehnout a lightweight to pak nezobrazi
|
||||
const sorter = (a, b) => a.time > b.time ? 1 : -1;
|
||||
|
||||
markers.sort(sorter)
|
||||
markers_line.sort(sorter)
|
||||
avgp_buy_line.sort(sorter)
|
||||
@ -287,118 +285,142 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
|
||||
//vybereme barvu pro kazdy identifikator
|
||||
//zjistime typ idenitfikatoru - zatim right vs left
|
||||
function display_indicators(data) {
|
||||
console.log("indikatory", JSON.stringify(data.indicators,null,2))
|
||||
//console.log("indikatory", JSON.stringify(data.indicators,null,2))
|
||||
//podobne v livewebsokcets.js - dat do jedne funkce
|
||||
if (data.hasOwnProperty("indicators")) {
|
||||
// console.log("jsme uvnitr indikatoru")
|
||||
var indicators = data.indicators
|
||||
//if there are indicators it means there must be at least two keys (time which is always present)
|
||||
if (Object.keys(indicators).length > 1) {
|
||||
for (const [key, value] of Object.entries(indicators)) {
|
||||
if (key !== "time") {
|
||||
//initialize indicator and store reference to array
|
||||
var obj = {name: key, series: null}
|
||||
|
||||
//start
|
||||
//console.log(key)
|
||||
//get configuation of indicator to display
|
||||
conf = get_ind_config(key)
|
||||
|
||||
//INIT INDICATOR BASED on CONFIGURATION
|
||||
//vraci se pole indicatoru, kazdy se svoji casovou osou (time) - nyni standard indikatory a cbar indikatory
|
||||
var indicatorList = data.indicators
|
||||
|
||||
//MOVE TO UTILS ro reuse??
|
||||
if (conf && conf.display) {
|
||||
indicatorList.forEach((indicators, index, array) => {
|
||||
|
||||
//tranform data do správného formátru
|
||||
items = []
|
||||
//var last = null
|
||||
value.forEach((element, index, array) => {
|
||||
item = {}
|
||||
//debug
|
||||
//TOTO odstranit po identifikovani chyby
|
||||
//if (indicators.time[index] !== undefined) {
|
||||
//{console.log("problem",key,last)}
|
||||
item["time"] = indicators.time[index]
|
||||
item["value"] = element
|
||||
//console.log("objekt indicatoru",item)
|
||||
items.push(item)
|
||||
//var indicators = data.indicators
|
||||
//if there are indicators it means there must be at least two keys (time which is always present)
|
||||
if (Object.keys(indicators).length > 1) {
|
||||
for (const [key, value] of Object.entries(indicators)) {
|
||||
if (key !== "time") {
|
||||
//initialize indicator and store reference to array
|
||||
var obj = {name: key, series: null}
|
||||
|
||||
//start
|
||||
//console.log(key)
|
||||
//get configuation of indicator to display
|
||||
conf = get_ind_config(key)
|
||||
|
||||
//INIT INDICATOR BASED on CONFIGURATION
|
||||
|
||||
//DO BUDOUCNA zde udelat sorter a pripadny handling duplicit jako
|
||||
//funkci do ktere muzu zavolat vse co pujde jako data do chartu
|
||||
|
||||
//MOVE TO UTILS ro reuse??
|
||||
if (conf && conf.display) {
|
||||
|
||||
//tranform data do správného formátru
|
||||
items = []
|
||||
//var last = null
|
||||
var last_time = 0
|
||||
var time = 0
|
||||
value.forEach((element, index, array) => {
|
||||
item = {}
|
||||
//debug
|
||||
//last = item
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// console.log("chybejici cas", key)
|
||||
// }
|
||||
});
|
||||
//TOTO odstranit po identifikovani chyby
|
||||
//if (indicators.time[index] !== undefined) {
|
||||
//{console.log("problem",key,last)}
|
||||
time = indicators.time[index]
|
||||
if (time==last_time) {
|
||||
//console.log(key, "problem v case - pousunuto o 0.001",time, last_time, element)
|
||||
time += 0.000001
|
||||
}
|
||||
item["time"] = time
|
||||
item["value"] = element
|
||||
|
||||
if (conf.embed) {
|
||||
last_time = time
|
||||
|
||||
if (conf.histogram) {
|
||||
if ((element == null) || (indicators.time[index] == null)) {
|
||||
console.log("probelem u indikatoru",key, "nekonzistence", element, indicators.time[index])
|
||||
}
|
||||
|
||||
//console.log("objekt indicatoru",item)
|
||||
items.push(item)
|
||||
//debug
|
||||
//last = item
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// console.log("chybejici cas", key)
|
||||
// }
|
||||
});
|
||||
|
||||
if (conf.embed) {
|
||||
|
||||
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,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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:",
|
||||
};
|
||||
//INDICATOR on new pane
|
||||
else { console.log("not implemented")}
|
||||
|
||||
const minSlopeLine = obj.series.createPriceLine(minSlopeLineOptopns);
|
||||
}
|
||||
}
|
||||
//add options
|
||||
obj.series.applyOptions({
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
|
||||
//console.log("problem tu",JSON.stringify(items))
|
||||
//add data
|
||||
obj.series.setData(items)
|
||||
|
||||
}
|
||||
//INDICATOR on new pane
|
||||
else { console.log("not implemented")}
|
||||
|
||||
//add options
|
||||
obj.series.applyOptions({
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
|
||||
//console.log("problem tu",items)
|
||||
//add data
|
||||
obj.series.setData(items)
|
||||
|
||||
// add to indList array - pole zobrazovanych indikatoru
|
||||
indList.push(obj);
|
||||
// add to indList array - pole zobrazovanych indikatoru
|
||||
indList.push(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//display vwap and volume
|
||||
|
||||
@ -5,6 +5,7 @@ var logcnt = 0
|
||||
var positionsPriceLine = null
|
||||
var limitkaPriceLine = null
|
||||
var angleSeries = 1
|
||||
var cbar = false
|
||||
|
||||
//get details of runner to populate chart status
|
||||
//fetch necessary - it could be initiated by manually inserting runnerId
|
||||
@ -53,35 +54,21 @@ function connect(event) {
|
||||
ws.onmessage = function(event) {
|
||||
var parsed_data = JSON.parse(event.data)
|
||||
|
||||
//console.log(JSON.stringify(parsed_data))
|
||||
console.log(JSON.stringify(parsed_data))
|
||||
|
||||
//check received data and display lines
|
||||
if (parsed_data.hasOwnProperty("bars")) {
|
||||
var bar = parsed_data.bars
|
||||
candlestickSeries.update(bar);
|
||||
volumeSeries.update({
|
||||
time: bar.time,
|
||||
value: bar.volume
|
||||
});
|
||||
vwapSeries.update({
|
||||
time: bar.time,
|
||||
value: bar.vwap
|
||||
});
|
||||
}
|
||||
|
||||
if (parsed_data.hasOwnProperty("bars")) {
|
||||
// console.log("mame bary")
|
||||
var bar = parsed_data.bars
|
||||
candlestickSeries.update(bar);
|
||||
volumeSeries.update({
|
||||
time: bar.time,
|
||||
value: bar.volume
|
||||
});
|
||||
vwapSeries.update({
|
||||
time: bar.time,
|
||||
value: bar.vwap
|
||||
});
|
||||
}
|
||||
// //check received data and display lines
|
||||
// if (parsed_data.hasOwnProperty("bars")) {
|
||||
// var bar = parsed_data.bars
|
||||
// candlestickSeries.update(bar);
|
||||
// volumeSeries.update({
|
||||
// time: bar.time,
|
||||
// value: bar.volume
|
||||
// });
|
||||
// vwapSeries.update({
|
||||
// time: bar.time,
|
||||
// value: bar.vwap
|
||||
// });
|
||||
// }
|
||||
|
||||
//loglist
|
||||
if (parsed_data.hasOwnProperty("iter_log")) {
|
||||
@ -344,6 +331,52 @@ function connect(event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed_data.hasOwnProperty("bars")) {
|
||||
|
||||
var bar = parsed_data.bars
|
||||
//pokud jde o cbary, tak jako time bereme cas posledniho update
|
||||
//aby se nam na grafu nepredbihaly cbar indikatory
|
||||
|
||||
//workaround pro identifikaci CBARU
|
||||
//pokud se vyskytne unconfirmed bar = jde o CBARY - nastavena globalni promena
|
||||
//standardni bar je vzdy potvrzeny
|
||||
// if (bar.confirmed == 0) {
|
||||
// cbar = true }
|
||||
|
||||
|
||||
// //pozor CBARY zobrazujeme na konci platnosti baru, nikoliv dle TIME, ale UPDATED
|
||||
// //kvuli navazovani prubeznych indikatoru na gui
|
||||
// if (cbar) {
|
||||
// // CBAR kreslime az po potvrzeni
|
||||
// if (bar.confirmed == 1) {
|
||||
// bar.time = bar.updated
|
||||
// candlestickSeries.update(bar);
|
||||
// volumeSeries.update({
|
||||
// time: bar.time,
|
||||
// value: bar.volume
|
||||
// });
|
||||
// vwapSeries.update({
|
||||
// time: bar.time,
|
||||
// value: bar.vwap
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// //time = bar.time
|
||||
|
||||
|
||||
candlestickSeries.update(bar);
|
||||
volumeSeries.update({
|
||||
time: bar.time,
|
||||
value: bar.volume
|
||||
});
|
||||
vwapSeries.update({
|
||||
time: bar.time,
|
||||
value: bar.vwap
|
||||
});
|
||||
//}
|
||||
}
|
||||
}
|
||||
ws.onclose = function(event) {
|
||||
document.getElementById("status").textContent = "Disconnected from" + runnerId.value
|
||||
|
||||
@ -9,6 +9,8 @@ var candlestickSeries = null
|
||||
var volumeSeries = null
|
||||
var vwapSeries = null
|
||||
|
||||
const sorter = (a, b) => a.time > b.time ? 1 : -1;
|
||||
|
||||
indConfig = {}
|
||||
settings = {}
|
||||
settings
|
||||
@ -16,6 +18,7 @@ settings
|
||||
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: "ivwap", titlevisible: true, embed: true, display: false, 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},
|
||||
|
||||
Binary file not shown.
@ -138,11 +138,12 @@ class Strategy:
|
||||
def save_item_history(self,item):
|
||||
if self.rectype == RecordType.BAR:
|
||||
#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.state.indicators['time'].append(item['updated'])
|
||||
else:
|
||||
self.state.indicators[key].append(0)
|
||||
self.append_bar(self.state.bars,item)
|
||||
elif self.rectype == RecordType.TRADE:
|
||||
pass
|
||||
@ -150,25 +151,42 @@ class Strategy:
|
||||
#self.state.indicators['time'].append(datetime.fromtimestamp(self.state.last_trade_time))
|
||||
#self.append_trade(self.state.trades,item)
|
||||
elif self.rectype == RecordType.CBAR:
|
||||
#novy vzdy pridame
|
||||
if self.nextnew:
|
||||
self.state.indicators['time'].append(item['updated'])
|
||||
#standardni identifikatory - populace hist zaznamu pouze v novem baru (dale se deji jen udpaty)
|
||||
for key in self.state.indicators:
|
||||
if key == 'time':
|
||||
continue
|
||||
self.state.indicators[key].append(0)
|
||||
self.state.indicators['time'].append(item['time'])
|
||||
else:
|
||||
self.state.indicators[key].append(0)
|
||||
|
||||
#cbar indikatory populace v kazde iteraci
|
||||
for key in self.state.cbar_indicators:
|
||||
if key == 'time':
|
||||
self.state.cbar_indicators['time'].append(item['updated'])
|
||||
else:
|
||||
self.state.cbar_indicators[key].append(0)
|
||||
|
||||
#populujeme i novy bar v historii
|
||||
self.append_bar(self.state.bars,item)
|
||||
self.nextnew = 0
|
||||
#nasledujici updatneme, po potvrzeni, nasleduje novy bar
|
||||
#nasledujici identifikatory v ramci cbaru take pridavame
|
||||
# (udrzujeme historii prubehu identifikatoru v ramci cbaru)
|
||||
else:
|
||||
#bary updatujeme, pridavame jen prvni
|
||||
self.replace_prev_bar(self.state.bars,item)
|
||||
|
||||
#u cbar indikatoru, pridavame kazdou zmenu ceny, krome potvrzeneho baru
|
||||
|
||||
if item['confirmed'] == 0:
|
||||
self.state.indicators['time'][-1]=item['updated']
|
||||
self.replace_prev_bar(self.state.bars,item)
|
||||
#confirmed
|
||||
#v naslednych updatech baru inicializujeme vzdy jen cbar indikatory
|
||||
for key in self.state.cbar_indicators:
|
||||
if key == 'time':
|
||||
self.state.cbar_indicators['time'].append(item['updated'])
|
||||
else:
|
||||
self.state.cbar_indicators[key].append(0)
|
||||
else:
|
||||
self.state.indicators['time'][-1]=item['updated']
|
||||
self.replace_prev_bar(self.state.bars,item)
|
||||
#pokud je potvrzeny, pak nenese nikdy zmenu ceny, nepridavame zaznam nic
|
||||
self.nextnew = 1
|
||||
|
||||
""""refresh positions and avgp - for CBAR once per confirmed, for BARS each time"""
|
||||
@ -395,11 +413,12 @@ class Strategy:
|
||||
##posilame dict s objekty: bars, trades podle cbaru, a dale indicators naplnene time a pripadnymi identifikatory (EMA)
|
||||
if self.rtqueue is not None:
|
||||
rt_out = dict()
|
||||
|
||||
|
||||
if self.rectype == RecordType.BAR or self.rectype == RecordType.CBAR:
|
||||
rt_out["bars"] = item
|
||||
else:
|
||||
rt_out["trades"] = item
|
||||
|
||||
#get only last values from indicators, if there are any indicators present
|
||||
if len(self.state.indicators) > 0:
|
||||
rt_out["indicators"] = dict()
|
||||
@ -410,6 +429,13 @@ class Strategy:
|
||||
#zatim takto odchycene identifikatory, ktere nemaji list, ale dict - do budoucna predelat na samostatny typ "indicators_static"
|
||||
except IndexError:
|
||||
pass
|
||||
#populate cbar indicators
|
||||
if len(self.state.cbar_indicators) > 0:
|
||||
for key, value in self.state.cbar_indicators.items():
|
||||
try:
|
||||
rt_out["indicators"][key]= value[-1]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
#same for static indicators
|
||||
if len(self.state.statinds) > 0:
|
||||
@ -544,6 +570,7 @@ class StrategyState:
|
||||
self.bars = AttributeDict(bars)
|
||||
self.trades = AttributeDict(trades)
|
||||
self.indicators = AttributeDict(time=[])
|
||||
self.cbar_indicators = AttributeDict(time=[])
|
||||
self.statinds = AttributeDict()
|
||||
#these methods can be overrided by StrategyType (to add or alter its functionality)
|
||||
self.buy = self.interface.buy
|
||||
|
||||
Binary file not shown.
@ -131,6 +131,14 @@ def price2dec(price: float, decimals: int = 2) -> float:
|
||||
"""
|
||||
return round(price,decimals) if count_decimals(price) > decimals else price
|
||||
|
||||
def round2five(price: float):
|
||||
"""
|
||||
zatim jen na 3 mista -pripadne predelat na dynamicky
|
||||
z 23.342 - 23.340
|
||||
z 23.346 - 23.345
|
||||
"""
|
||||
return (round(price*100*2)/2)/100
|
||||
|
||||
def count_decimals(number: float) -> int:
|
||||
"""
|
||||
Count the number of decimals in a given float: 1.4335 -> 4 or 3 -> 0
|
||||
|
||||
Reference in New Issue
Block a user