SL do grafu, pred zmenou signal podminek

This commit is contained in:
David Brazda
2023-08-30 15:23:01 +02:00
parent 4a3d5ddfe4
commit 9bad9b850a
10 changed files with 246 additions and 100 deletions

View File

@ -7,6 +7,7 @@ from v2realbot.indicators.indicators import ema
from v2realbot.indicators.oscillators import rsi from v2realbot.indicators.oscillators import rsi
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, round2five, is_open_rush, is_close_rush, eval_cond_dict, Average, crossed_down, crossed_up, crossed, is_pivot, json_serial from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, round2five, is_open_rush, is_close_rush, eval_cond_dict, Average, crossed_down, crossed_up, crossed, is_pivot, json_serial
from v2realbot.common.model import SLHistory
from datetime import datetime from datetime import datetime
from uuid import uuid4 from uuid import uuid4
import json import json
@ -498,20 +499,25 @@ def next(data, state: StrategyState):
lookbacktime = state.bars.time[-slope_lookback] lookbacktime = state.bars.time[-slope_lookback]
else: else:
#kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0] #kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0]
lookbackprice = state.bars.vwap[0]
#pokud neni dostatek, bereme vzdy petinu ze stávajících barů
# cnt = len(state.bars.close)
# if cnt>5:
# sliced_to = int(cnt/5)
# lookbackprice= Average(state.bars.vwap[:sliced_to])
# else:
#lookbackprice = state.bars.vwap[0] #lookbackprice = state.bars.vwap[0]
#update -- lookback je pole z toho co mame
#dalsi vyarianta-- lookback je pole z toho všeho co mame
#lookbackprice = Average(state.bars.vwap) #lookbackprice = Average(state.bars.vwap)
#pokud neni dostatek, bereme vzdy prvni petinu z dostupnych barů
# a z ní uděláme průměr
cnt = len(state.bars.close)
if cnt>5:
sliced_to = int(cnt/5)
lookbackprice= Average(state.bars.vwap[:sliced_to])
lookbacktime = state.bars.time[int(sliced_to/2)]
else:
lookbackprice = Average(state.bars.vwap)
lookbacktime = state.bars.time[0] lookbacktime = state.bars.time[0]
state.ilog(e=f"IND {name} slope - not enough data bereme left bod open", slope_lookback=slope_lookback)
state.ilog(e=f"IND {name} slope - not enough data bereme left bod open", slope_lookback=slope_lookback, lookbackprice=lookbackprice)
#výpočet úhlu - a jeho normalizace #výpočet úhlu - a jeho normalizace
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100 slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
@ -533,7 +539,7 @@ def next(data, state: StrategyState):
state.indicators[name+"MA"][-1]=slopeMA state.indicators[name+"MA"][-1]=slopeMA
last_slopesMA = state.indicators[name+"MA"][-10:] last_slopesMA = state.indicators[name+"MA"][-10:]
state.ilog(e=f"{name=} {slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators[name][-10:], last_slopesMA=last_slopesMA) state.ilog(e=f"{name=} {slope=} {slopeMA=}", msg=f"{lookbackprice=} {lookbacktime=}", slope_lookback=slope_lookback, lookbackoffset=lookback_offset, lookbacktime=lookbacktime, minimum_slope=minimum_slope, last_slopes=state.indicators[name][-10:], last_slopesMA=last_slopesMA)
#dale pracujeme s timto MAckovanym slope #dale pracujeme s timto MAckovanym slope
#slope = slopeMA #slope = slopeMA
@ -752,7 +758,11 @@ def next(data, state: StrategyState):
# return result # return result
def trail_SL_if_required(direction: TradeDirection): def insert_SL_history():
#insert stoploss history as key sl_history into runner archive extended data
state.extData["sl_history"].append(SLHistory(id=state.vars.activeTrade.id, time=state.time, sl_val=state.vars.activeTrade.stoploss_value))
def trail_SL_management():
#pokud se cena posouva nasim smerem olespon o (0.05) nad (SL + 0.09val), posuneme SL o offset #pokud se cena posouva nasim smerem olespon o (0.05) nad (SL + 0.09val), posuneme SL o offset
#+ varianta - skoncit breakeven #+ varianta - skoncit breakeven
@ -768,10 +778,14 @@ def next(data, state: StrategyState):
# #zda trailing zastavit na brakeeven # #zda trailing zastavit na brakeeven
# SL_trailing_stop_at_breakeven_short = true # SL_trailing_stop_at_breakeven_short = true
# SL_trailing_stop_at_breakeven_long = true # SL_trailing_stop_at_breakeven_long = true
if direction == TradeDirection.LONG: if int(state.positions) != 0 and float(state.avgp)>0 and state.vars.pending is None:
smer = "long"
else: if int(state.positions) < 0:
direction = TradeDirection.SHORT
smer = "short" smer = "short"
else:
direction = TradeDirection.LONG
smer = "long"
options = safe_get(state.vars, 'exit_conditions', None) options = safe_get(state.vars, 'exit_conditions', None)
if options is None: if options is None:
@ -785,7 +799,7 @@ def next(data, state: StrategyState):
#pokud je pozadovan trail jen do breakeven a uz prekroceno #pokud je pozadovan trail jen do breakeven a uz prekroceno
if (direction == TradeDirection.LONG and stop_breakeven and state.vars.activeTrade.stoploss_value >= float(state.avgp)) or (direction == TradeDirection.SHORT and stop_breakeven and state.vars.activeTrade.stoploss_value <= float(state.avgp)): if (direction == TradeDirection.LONG and stop_breakeven and state.vars.activeTrade.stoploss_value >= float(state.avgp)) or (direction == TradeDirection.SHORT and stop_breakeven and state.vars.activeTrade.stoploss_value <= float(state.avgp)):
state.ilog(e=f"SL trail stop at breakeven {str(smer)} SL:{state.vars.activeTrade.stoploss_value} UNCHANGED", stop_breakeven=stop_breakeven) state.ilog(e=f"SL trail STOP at breakeven {str(smer)} SL:{state.vars.activeTrade.stoploss_value} UNCHANGED", stop_breakeven=stop_breakeven)
return return
#IDEA: Nyni posouvame SL o offset, mozna ji posunout jen o direktivu step ? #IDEA: Nyni posouvame SL o offset, mozna ji posunout jen o direktivu step ?
@ -794,17 +808,38 @@ def next(data, state: StrategyState):
def_SL_normalized = normalize_tick(def_SL) def_SL_normalized = normalize_tick(def_SL)
if direction == TradeDirection.LONG: if direction == TradeDirection.LONG:
move_SL_threshold = state.vars.activeTrade.stoploss_value + offset_normalized + def_SL_normalized move_SL_threshold = state.vars.activeTrade.stoploss_value + offset_normalized + def_SL_normalized
state.ilog(e=f"SL trailing EVAL {smer} SL:{state.vars.activeTrade.stoploss_value} MOVETHRESHOLD:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized) state.ilog(e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
if (move_SL_threshold) < data['close']: if (move_SL_threshold) < data['close']:
state.vars.activeTrade.stoploss_value += offset_normalized state.vars.activeTrade.stoploss_value += offset_normalized
insert_SL_history()
state.ilog(e=f"SL TRAIL TH {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized) state.ilog(e=f"SL TRAIL TH {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
elif direction == TradeDirection.SHORT: elif direction == TradeDirection.SHORT:
move_SL_threshold = state.vars.activeTrade.stoploss_value - offset_normalized - def_SL_normalized move_SL_threshold = state.vars.activeTrade.stoploss_value - offset_normalized - def_SL_normalized
state.ilog(e=f"SL trailing EVAL {smer} SL:{state.vars.activeTrade.stoploss_value} MOVETHRESHOLD:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized) state.ilog(e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
if (move_SL_threshold) > data['close']: if (move_SL_threshold) > data['close']:
state.vars.activeTrade.stoploss_value -= offset_normalized state.vars.activeTrade.stoploss_value -= offset_normalized
state.ilog(e=f"SL TRAIL TH {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized) insert_SL_history()
state.ilog(e=f"SL TRAIL GOAL {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
def close_position(direction: TradeDirection, reason: str):
state.ilog(e=f"CLOSING TRADE {reason} {str(direction)}", curr_price=data["close"], trade=state.vars.activeTrade)
if direction == TradeDirection.SHORT:
res = state.buy(size=abs(int(state.positions)))
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation {reason} {res}")
elif direction == TradeDirection.LONG:
res = state.sell(size=state.positions)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation STOPLOSS SELL {res}")
else:
raise Exception(f"unknow TradeDirection in close_position")
#pri uzavreni tradu zapisujeme SL history - lepsi zorbazeni v grafu
insert_SL_history()
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
def eval_close_position(): def eval_close_position():
curr_price = float(data['close']) curr_price = float(data['close'])
@ -817,32 +852,21 @@ def next(data, state: StrategyState):
state.ilog(e=f"Goal price {goal_price} max price {max_price}") state.ilog(e=f"Goal price {goal_price} max price {max_price}")
#close position handling #close position handling
#TBD pridat OPTIMALIZACI POZICE - EXIT 1/2
#mame short pozice - (IDEA: rozlisovat na zaklade aktivniho tradu - umozni mi spoustet i long pozicemi) #mame short pozice - (IDEA: rozlisovat na zaklade aktivniho tradu - umozni mi spoustet i pri soucasne long pozicemi)
if int(state.positions) < 0: if int(state.positions) < 0:
#EOD EXIT - TBD #EOD EXIT - TBD
#FORCED EXIT PRI KONCI DNE
#SL TRAILING
trail_SL_if_required(direction=TradeDirection.SHORT)
#SL - execution #SL - execution
if curr_price > state.vars.activeTrade.stoploss_value: if curr_price > state.vars.activeTrade.stoploss_value:
state.ilog(e=f"STOPLOSS reached on SHORT", curr_price=curr_price, trade=state.vars.activeTrade) close_position(direction=TradeDirection.SHORT, reason="SL REACHED")
res = state.buy(size=abs(int(state.positions)))
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation STOPLOSS BUY {res}")
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
return return
#CLOSING BASED ON EXIT CONDITIONS #CLOSING BASED ON EXIT CONDITIONS
if exit_conditions_met(TradeDirection.SHORT): if exit_conditions_met(TradeDirection.SHORT):
res = state.buy(size=abs(int(state.positions))) close_position(direction=TradeDirection.SHORT, reason="EXIT COND MET")
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation EXIT COND BUY {res}")
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
state.ilog(e=f"EXIT COND MET. market BUY was sent {curr_price=}", positions=state.positions, avgp=state.avgp)
return return
#PROFIT #PROFIT
@ -853,37 +877,19 @@ def next(data, state: StrategyState):
max_price_signal = curr_price<=max_price max_price_signal = curr_price<=max_price
#OPTIMALIZACE pri stoupajícím angle #OPTIMALIZACE pri stoupajícím angle
if max_price_signal or sell_protection_enabled() is False: if max_price_signal or sell_protection_enabled() is False:
res = state.buy(size=abs(int(state.positions))) close_position(direction=TradeDirection.SHORT, reason=f"PROFIT or MAXPROFIT REACHED {max_price_signal=}")
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation PROFIT BUY {res}")
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
state.ilog(e=f"PROFIT MET EXIT. market BUY was sent {curr_price=} {max_price_signal=}", positions=state.positions, avgp=state.avgp)
return return
#mame long #mame long
elif int(state.positions) > 0: elif int(state.positions) > 0:
#EOD EXIT - TBD #EOD EXIT - TBD
#SL - trailing
trail_SL_if_required(direction=TradeDirection.LONG)
#SL - execution #SL - execution
if curr_price < state.vars.activeTrade.stoploss_value: if curr_price < state.vars.activeTrade.stoploss_value:
state.ilog(e=f"STOPLOSS reached on LONG", curr_price=curr_price, trade=state.vars.activeTrade) close_position(direction=TradeDirection.LONG, reason="SL REACHED")
res = state.sell(size=state.positions)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation STOPLOSS SELL {res}")
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
return return
if exit_conditions_met(TradeDirection.LONG): if exit_conditions_met(TradeDirection.LONG):
res = state.sell(size=abs(int(state.positions))) close_position(direction=TradeDirection.LONG, reason="EXIT CONDS MET")
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation EXIT COND SELL {res}")
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
state.ilog(e=f"EXIT COND MET. market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp)
return return
#PROFIT #PROFIT
@ -894,12 +900,7 @@ def next(data, state: StrategyState):
max_price_signal = curr_price>=max_price max_price_signal = curr_price>=max_price
#OPTIMALIZACE pri stoupajícím angle #OPTIMALIZACE pri stoupajícím angle
if max_price_signal or sell_protection_enabled() is False: if max_price_signal or sell_protection_enabled() is False:
res = state.sell(size=state.positions) close_position(direction=TradeDirection.LONG, reason=f"PROFIT or MAXPROFIT REACHED {max_price_signal=}")
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation PROFIT SELL {res}")
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
state.ilog(e=f"PROFIT MET EXIT. market SELL was sent {curr_price=} {max_price_signal=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress)
return return
def execute_prescribed_trades(): def execute_prescribed_trades():
@ -939,6 +940,7 @@ def next(data, state: StrategyState):
#normalizuji dle aktualni ceny #normalizuji dle aktualni ceny
sl_defvalue_normalized = normalize_tick(sl_defvalue) sl_defvalue_normalized = normalize_tick(sl_defvalue)
state.vars.activeTrade.stoploss_value = float(data['close']) - sl_defvalue_normalized state.vars.activeTrade.stoploss_value = float(data['close']) - sl_defvalue_normalized
insert_SL_history()
state.ilog(e=f"Nastaveno SL na {sl_defvalue}, priced normalized: {sl_defvalue_normalized} price: {state.vars.activeTrade.stoploss_value }") state.ilog(e=f"Nastaveno SL na {sl_defvalue}, priced normalized: {sl_defvalue_normalized} price: {state.vars.activeTrade.stoploss_value }")
state.vars.pending = state.vars.activeTrade.id state.vars.pending = state.vars.activeTrade.id
elif state.vars.activeTrade.direction == TradeDirection.SHORT: elif state.vars.activeTrade.direction == TradeDirection.SHORT:
@ -952,6 +954,7 @@ def next(data, state: StrategyState):
#normalizuji dle aktualni ceny #normalizuji dle aktualni ceny
sl_defvalue_normalized = normalize_tick(sl_defvalue) sl_defvalue_normalized = normalize_tick(sl_defvalue)
state.vars.activeTrade.stoploss_value = float(data['close']) + sl_defvalue_normalized state.vars.activeTrade.stoploss_value = float(data['close']) + sl_defvalue_normalized
insert_SL_history()
state.ilog(e=f"Nastaveno SL na {sl_defvalue}, priced normalized: {sl_defvalue_normalized} price: {state.vars.activeTrade.stoploss_value }") state.ilog(e=f"Nastaveno SL na {sl_defvalue}, priced normalized: {sl_defvalue_normalized} price: {state.vars.activeTrade.stoploss_value }")
state.vars.pending = state.vars.activeTrade.id state.vars.pending = state.vars.activeTrade.id
else: else:
@ -966,7 +969,7 @@ def next(data, state: StrategyState):
def execute_asr(): def execute_asr():
pass pass
#preconditions and conditions of BUY SIGNAL #preconditions and conditions of LONG/SHORT SIGNAL
def conditions_met(signalname: str, direction: TradeDirection): def conditions_met(signalname: str, direction: TradeDirection):
if direction == TradeDirection.LONG: if direction == TradeDirection.LONG:
smer = "long" smer = "long"
@ -989,6 +992,8 @@ def next(data, state: StrategyState):
# dont_buy_when['last_buy_offset_too_soon'] = data['index'] < (int(state.vars.lastbuyindex) + int(safe_get(state.vars, "lastbuy_offset",3))) # dont_buy_when['last_buy_offset_too_soon'] = data['index'] < (int(state.vars.lastbuyindex) + int(safe_get(state.vars, "lastbuy_offset",3)))
# dont_buy_when['blockbuy_active'] = (state.vars.blockbuy == 1) # dont_buy_when['blockbuy_active'] = (state.vars.blockbuy == 1)
# dont_buy_when['jevylozeno_active'] = (state.vars.jevylozeno == 1) # dont_buy_when['jevylozeno_active'] = (state.vars.jevylozeno == 1)
#obecne open_rush platne pro vsechny
dont_do_when['open_rush'] = is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "open_rush",0)) dont_do_when['open_rush'] = is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "open_rush",0))
dont_do_when['close_rush'] = is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "close_rush",0)) dont_do_when['close_rush'] = is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "close_rush",0))
@ -1065,14 +1070,27 @@ def next(data, state: StrategyState):
state.ilog(e="No options for {name} in stratvars") state.ilog(e="No options for {name} in stratvars")
return return
validfrom = safe_get(options, "validfrom", 0) #check working windows
validto = safe_get(options, "validto", 0) close_rush = safe_get(options, "close_rush",0)
open_rush = safe_get(options, "open_rush",0)
if is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), open_rush) or is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), close_rush):
state.ilog(e="SINGAL {name} OUT of WORKING WINDOW", msg=f"{open_rush=} {close_rush=} ")
return
#natvrdo nebo na podminku
activated = safe_get(options, "activated", True)
recurring = safe_get(options, "reccurring", False) recurring = safe_get(options, "reccurring", False)
on_confirmed_only = safe_get(options, 'on_confirmed_only', False) on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
plugin = safe_get(options, 'plugin', None) plugin = safe_get(options, 'plugin', None)
short_enabled = safe_get(state.vars, "short_enabled",True) short_enabled = safe_get(state.vars, "short_enabled",True)
long_enabled = safe_get(state.vars, "long_enabled",True) long_enabled = safe_get(state.vars, "long_enabled",True)
if activated is False:
state.ilog(e="SIGNAL {name} NOT ACTIVATED")
return
#pokud je plugin True, spusti se kod #pokud je plugin True, spusti se kod
if plugin: if plugin:
execute_signal_generator_plugin(name) execute_signal_generator_plugin(name)
@ -1122,6 +1140,9 @@ def next(data, state: StrategyState):
if trade is None: if trade is None:
return -1 return -1
#SL - trailing
trail_SL_management()
eval_close_position() eval_close_position()
#SELL STOPLOSS #SELL STOPLOSS
#SELL PROFIT #SELL PROFIT
@ -1204,8 +1225,10 @@ def init(state: StrategyState):
state.vars.work_dict_dont_do[signalname+"_"+ smer] = get_work_dict_with_directive(starts_with=signalname+"_dont_"+ smer +"_if") state.vars.work_dict_dont_do[signalname+"_"+ smer] = get_work_dict_with_directive(starts_with=signalname+"_dont_"+ smer +"_if")
state.vars.work_dict_signal_if[signalname+"_"+ smer] = get_work_dict_with_directive(starts_with=signalname+"_"+smer+"_if") state.vars.work_dict_signal_if[signalname+"_"+ smer] = get_work_dict_with_directive(starts_with=signalname+"_"+smer+"_if")
#nove atributy na rizeni tradu #init klice v extData pro ulozeni historie SL
state.extData["sl_history"] = []
#nove atributy na rizeni tradu
#identifikuje provedenou změnu na Tradu (neděláme změny dokud nepřijde potvrzeni z notifikace) #identifikuje provedenou změnu na Tradu (neděláme změny dokud nepřijde potvrzeni z notifikace)
state.vars.pending = None state.vars.pending = None
#obsahuje aktivni Trade a jeho nastaveni #obsahuje aktivni Trade a jeho nastaveni

View File

@ -199,6 +199,12 @@ class RunArchive(BaseModel):
end_positions_avgp: float = 0 end_positions_avgp: float = 0
open_orders: Union[dict, int] = None open_orders: Union[dict, int] = None
#trida pro ukladani historie stoplossy do ext_data
class SLHistory(BaseModel):
id: Optional[UUID]
time: datetime
sl_val: float
#Contains archive of running strategies (runner) - detail data #Contains archive of running strategies (runner) - detail data
class RunArchiveDetail(BaseModel): class RunArchiveDetail(BaseModel):
id: UUID id: UUID
@ -208,6 +214,7 @@ class RunArchiveDetail(BaseModel):
indicators: List[dict] indicators: List[dict]
statinds: dict statinds: dict
trades: List[TradeUpdate] trades: List[TradeUpdate]
ext_data: Optional[dict]
# class Trade(BaseModel): # class Trade(BaseModel):
# order: Order # order: Order

View File

@ -595,12 +595,14 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
# flattened_indicators[key]= value # flattened_indicators[key]= value
# flattened_indicators_list.append(flattened_indicators) # flattened_indicators_list.append(flattened_indicators)
runArchiveDetail: RunArchiveDetail = RunArchiveDetail(id = runner.id, runArchiveDetail: RunArchiveDetail = RunArchiveDetail(id = runner.id,
name=runner.run_name, name=runner.run_name,
bars=strat.state.bars, bars=strat.state.bars,
indicators=flattened_indicators_list, indicators=flattened_indicators_list,
statinds=strat.state.statinds, statinds=strat.state.statinds,
trades=strat.state.tradeList) trades=strat.state.tradeList,
ext_data=strat.state.extData)
with lock: with lock:
resh = db_arch_h.insert(runArchive.__dict__) resh = db_arch_h.insert(runArchive.__dict__)
resd = insert_archive_detail(runArchiveDetail) resd = insert_archive_detail(runArchiveDetail)

View File

@ -5,6 +5,7 @@ var CHART_SHOW_TEXT = false
// var volumeSeries = null // var volumeSeries = null
var markersLine = null var markersLine = null
var avgBuyLine = null var avgBuyLine = null
var slLine = []
//TRANSFORM object returned from REST API get_arch_run_detail //TRANSFORM object returned from REST API get_arch_run_detail
//to series and markers required by lightweigth chart //to series and markers required by lightweigth chart
//input array object bars = { high: [1,2,3], time: [1,2,3], close: [2,2,2]...} //input array object bars = { high: [1,2,3], time: [1,2,3], close: [2,2,2]...}
@ -15,6 +16,49 @@ function transform_data(data) {
var bars = [] var bars = []
var volume = [] var volume = []
var vwap = [] var vwap = []
//pokud mame tak projedeme ext_data pro dane klice a s nimi pracujeme
var sl_line = []
var sl_line_markers = []
var sl_line_sada = []
var sl_line_markers_sada = []
//console.log(JSON.stringify(data.ext_data.sl_history, null, 2))
prev_id = 0
data.ext_data.sl_history.forEach((histRecord, index, array) => {
console.log("plnime")
//nova sada
if (prev_id !== histRecord.id) {
if (prev_id !== 0) {
//push sadu do pole
sl_line.push(sl_line_sada)
sl_line_markers.push(sl_line_markers_sada)
}
//init nova sada
sl_line_sada = []
sl_line_markers_sada = []
}
prev_id = histRecord.id
//prevedeme iso data na timestampy
cas = histRecord.time
//line pro buy/sell markery
sline = {}
sline["time"] = cas
sline["value"] = histRecord.sl_val
sl_line_sada.push(sline)
sline_markers = {}
sline_markers["time"] = cas
sline_markers["position"] = "inBar"
sline_markers["color"] = "#f5aa42"
//sline_markers["shape"] = "circle"
sline_markers["text"] = histRecord.sl_val.toFixed(3)
sl_line_markers_sada.push(sline_markers)
});
data.bars.time.forEach((element, index, array) => { data.bars.time.forEach((element, index, array) => {
sbars = {}; sbars = {};
svolume = {}; svolume = {};
@ -117,7 +161,7 @@ function transform_data(data) {
marker["text"] += (trade.position_qty == 0) ? closed_trade_marker_and_profit : "" marker["text"] += (trade.position_qty == 0) ? closed_trade_marker_and_profit : ""
} else { } else {
closed_trade_marker_and_profit = (trade.profit) ? "c" + trade.profit.toFixed(1) + "/" + trade.profit_sum.toFixed(1) : "c" closed_trade_marker_and_profit = (trade.profit) ? "c" + trade.profit.toFixed(1) + "/" + trade.profit_sum.toFixed(1) : "c"
marker["text"] = (trade.position_qty == 0) ? closed_trade_marker_and_profit : "" marker["text"] = (trade.position_qty == 0) ? closed_trade_marker_and_profit : trade.price.toFixed(3)
} }
markers.push(marker) markers.push(marker)
@ -153,7 +197,11 @@ function transform_data(data) {
transformed["avgp_markers"] = avgp_markers transformed["avgp_markers"] = avgp_markers
transformed["markers"] = markers transformed["markers"] = markers
transformed["markers_line"] = markers_line transformed["markers_line"] = markers_line
transformed["sl_line"] = sl_line
transformed["sl_line_markers"] = sl_line_markers
console.log("naplnene", sl_line, sl_line_markers)
//console_log(JSON.stringify(transformed["sl_line"],null,2))
//console_log(JSON.stringify(transformed["sl_line_markers"],null,2))
//get additional indicators //get additional indicators
return transformed return transformed
} }
@ -541,9 +589,45 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
chart.removeSeries(markersLine) chart.removeSeries(markersLine)
} }
slLine.forEach((series, index, array) => {
chart.removeSeries(series)
})
// if (slLine) {
// chart.removeSeries(slLine)
// }
//console.log("avgp_buy_line",JSON.stringify(transformed_data["avgp_buy_line"],null,2)) //console.log("avgp_buy_line",JSON.stringify(transformed_data["avgp_buy_line"],null,2))
//console.log("avgp_markers",JSON.stringify(transformed_data["avgp_markers"],null,2)) //console.log("avgp_markers",JSON.stringify(transformed_data["avgp_markers"],null,2))
//if (transformed_data["sl_line"].length > 0) {
//console.log(JSON.stringify(transformed_data["sl_line"]), null,2)
//xx - ted bude slLine pole
transformed_data["sl_line"].forEach((slRecord, index, array) => {
console.log("uvnitr")
slLine_temp = chart.addLineSeries({
// title: "avgpbuyline",
color: '#e4c76d',
// color: 'transparent',
lineWidth: 1,
lastValueVisible: false
});
slLine_temp.applyOptions({
lastValueVisible: false,
priceLineVisible: false,
});
slLine_temp.setData(slRecord);
//zatim nemame markery pro sl history
slLine_temp.setMarkers(transformed_data["sl_line_markers"][index]);
slLine.push(slLine_temp)
//xx
})
//}
if (transformed_data["avgp_buy_line"].length > 0) { if (transformed_data["avgp_buy_line"].length > 0) {
avgBuyLine = chart.addLineSeries({ avgBuyLine = chart.addLineSeries({
// title: "avgpbuyline", // title: "avgpbuyline",

View File

@ -3,6 +3,7 @@ var pbiList = []
var ws = null; var ws = null;
var logcnt = 0 var logcnt = 0
var positionsPriceLine = null var positionsPriceLine = null
var stoplossPriceLine = null
var limitkaPriceLine = null var limitkaPriceLine = null
var angleSeries = {} var angleSeries = {}
//var angleSeries_slow = 1 //var angleSeries_slow = 1
@ -200,6 +201,24 @@ function connect(event) {
candlestickSeries.removePriceLine(positionsPriceLine) candlestickSeries.removePriceLine(positionsPriceLine)
} }
positionsPriceLine = candlestickSeries.createPriceLine(posLine); positionsPriceLine = candlestickSeries.createPriceLine(posLine);
if (positions.sl_value !== null) {
if (stoplossPriceLine !== null) {
candlestickSeries.removePriceLine(stoplossPriceLine)
}
const stoplossLine = {
price: positions.sl_value,
color: '#f5aa42',
lineWidth: 1,
lineStyle: 1, // LineStyle.Dotted
axisLabelVisible: true,
title: "SL",
};
stoplossPriceLine = candlestickSeries.createPriceLine(stoplossLine);
}
} }
if (parsed_data.hasOwnProperty("statinds")) { if (parsed_data.hasOwnProperty("statinds")) {

View File

@ -514,7 +514,14 @@ class Strategy:
#vkladame average price and positions, pokud existuji #vkladame average price and positions, pokud existuji
#self.state.avgp , self.state.positions #self.state.avgp , self.state.positions
rt_out["positions"] = dict(time=self.state.time, positions=self.state.positions, avgp=self.state.avgp)
#pro typ strategie Classic, posilame i vysi stoploss
try:
sl_value = self.state.vars["activeTrade"].stoploss_value
except (KeyError, AttributeError):
sl_value = None
rt_out["positions"] = dict(time=self.state.time, positions=self.state.positions, avgp=self.state.avgp, sl_value=sl_value)
#vkladame limitku a pendingbuys #vkladame limitku a pendingbuys
try: try:
@ -652,6 +659,8 @@ class StrategyState:
self.iter_log_list = [] self.iter_log_list = []
self.profit = 0 self.profit = 0
self.tradeList = [] self.tradeList = []
#nova promenna pro externi data do ArchiveDetaili, napr. pro zobrazeni v grafu, je zde např. SL history
self.extData = {}
self.mode = None self.mode = None
def ilog(self, e: str = None, msg: str = None, **kwargs): def ilog(self, e: str = None, msg: str = None, **kwargs):

View File

@ -9,7 +9,7 @@ import decimal
from v2realbot.enums.enums import RecordType, Mode, StartBarAlign from v2realbot.enums.enums import RecordType, Mode, StartBarAlign
import pickle import pickle
import os import os
from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals, SLHistory
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
from typing import List from typing import List
import tomli import tomli
@ -208,6 +208,8 @@ def json_serial(obj):
return obj.__dict__ return obj.__dict__
if type(obj) is Intervals: if type(obj) is Intervals:
return obj.__dict__ return obj.__dict__
if type(obj) is SLHistory:
return obj.__dict__
raise TypeError (str(obj)+"Type %s not serializable" % type(obj)) raise TypeError (str(obj)+"Type %s not serializable" % type(obj))