pridan zaklad k custom indikatorum

This commit is contained in:
David Brazda
2023-09-10 21:20:22 +02:00
parent e08ae0f537
commit f568f62687
10 changed files with 621 additions and 67 deletions

23
testy/evalscope.py Normal file
View File

@ -0,0 +1,23 @@
# def my_function():
# return "Hello, World!"
# def call_function_by_name():
# func_name = "my_function"
# # Use eval to call the function
# result = eval(func_name)()
def my_function():
return "Hello, World!"
def call_function_by_name():
# Create a closure to capture the my_function function
def inner_function():
return eval("my_function")()
result = inner_function()
return result
print(call_function_by_name())

184
testy/higherhighs.py Normal file
View File

@ -0,0 +1,184 @@
def is_rising_trend(price_list):
"""
This function determines whether prices are consistently creating higher highs and higher lows.
Args:
price_list: A list of prices.
Returns:
True if the prices are in a rising trend, False otherwise.
"""
if len(price_list) < 2:
return False
#
global last_last_low
global last_high
global last_low
global last_last_high
global last_last_low
last_high = price_list[0]
last_low = None
last_last_high = price_list[0]
last_last_low = price_list[0]
print(price_list)
for i in range(1, len(price_list)):
print("processing",price_list[i])
#pokud je dalsi rostouci
if price_list[i] > price_list[i-1]:
#je vetsi nez LH - stává se LH
if price_list[i] > last_high:
#last_last_high = last_high
last_high = price_list[i]
#print("nova last last high",last_last_high)
print("nove last high",last_high)
#pokud je klesajici
elif price_list[i] < price_list[i-1]:
#pokud je cena nad last last jsme ok
if price_list[i] > last_last_low:
if last_low is None or price_list[i] < last_low:
if last_low is not None:
#vytvorime nove last last low
last_last_low = last_low
print("nova last last low",last_last_low)
#rovnou porovname cenu zda neklesla
if price_list[i] < last_last_low:
print("kleslo pod last last low")
return False
#mame nove last low
last_low = price_list[i]
print("nove last low",last_low)
else:
print("kleslo pod last last low, neroste")
return False
print("funkce skoncila, stale roste")
return True
# Example usage:
#price_list = [1,2,3,2,2.5,3,1.8,4,5,4,4.5,4.3,4.8,4.5,6]
price_list = [
# -0.0106,
# -0.001,
# 0.0133,
# 0.0116,
# 0.0075,
-0.015,
-0.0142,
-0.0071,
-0.0077,
-0.0083,
0.0016,
0.0266,
0.0355,
0.0455,
0.0563,
0.1064,
0.1283,
0.1271,
0.1277,
0.1355,
0.152,
0.1376,
0.1164,
0.1115,
0.102,
0.0808,
0.0699,
0.0625,
0.0593,
0.0485,
0.0323,
0.0382,
0.0403,
0.0441,
0.0526,
0.0728,
0.0841,
0.1029,
0.1055,
0.0964,
0.0841,
0.0677,
0.0782,
0.0877,
0.1099,
0.1215,
0.1379,
0.1234,
0.1,
0.0949,
0.1133,
0.1428,
0.1525,
0.166,
0.1788,
0.1901,
0.1967,
0.2099,
0.2407,
0.2719,
0.2897,
0.3101,
0.331,
0.328,
0.3241,
0.3258,
0.3275,
0.3188,
0.3071,
0.2942,
0.2939,
0.277,
0.2498,
0.2464,
0.2413,
0.2377,
0.2112,
0.2076,
0.2018,
0.1975,
0.1814,
0.1776,
0.1761,
0.1868,
0.1961,
0.2016,
0.2313,
0.2485,
0.2668,
0.2973,
0.3278,
0.3581,
0.3893,
0.3997,
0.4176,
0.4285,
0.4369,
0.4457,
0.4524,
0.4482,
0.4439,
0.4302,
0.4205,
0.4278,
0.4345,
0.4403,
0.4504,
0.4523,
0.461,
0.4649,
0.4618,
0.4675,
0.4724]
result = is_rising_trend(price_list)
print(result) # This will print [(4, 60), (7, 62)] for the provided example

View File

@ -9,9 +9,10 @@ from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeSt
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, round2five, is_open_rush, is_close_rush, is_still, is_window_open, eval_cond_dict, Average, crossed_down, crossed_up, crossed, is_pivot, json_serial
from v2realbot.utils.directive_utils import get_conditions_from_configuration
from v2realbot.common.model import SLHistory
from datetime import datetime
from datetime import datetime, timedelta
from v2realbot.config import KW
from uuid import uuid4
import random
import json
#from icecream import install, ic
#from rich import print
@ -250,9 +251,174 @@ def next(data, state: StrategyState):
populate_dynamic_ema_indicator(name = name)
elif type == "NATR":
populate_dynamic_natr_indicator(name = name)
elif type == "custom":
populate_dynamic_custom_indicator(name = name)
else:
return
#WIP -
def populate_dynamic_custom_indicator(name):
ind_type = "custom"
options = safe_get(state.vars.indicators, name, None)
if options is None:
state.ilog(e=f"No options for {name} in stratvars")
return
if safe_get(options, "type", False) is False or safe_get(options, "type", False) != ind_type:
state.ilog(e="Type error")
return
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
subtype = safe_get(options, 'subtype', False)
if subtype is False:
state.ilog(e=f"No subtype for {name} in stratvars")
return
#if MA is required
MA_length = safe_get(options, "MA_length", None)
def is_time_to_run():
# on_confirmed_only = true (def. False)
# start_at_bar_index = 2 (def. None)
# start_at_time = "9:31" (def. None)
# repeat_every_Nbar = N (def.None) (opakovat každý N bar, 1 - každý bar, 2 - každý 2., 0 - pouze jednou)
# repeat_every_Nmin = N (def. None) opakovat každých N minut
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
start_at_bar_index = safe_get(options, 'start_at_bar_index', None)
start_at_time = safe_get(options, 'start_at_time', None) # "9:30"
repeat_every_Nbar = safe_get(options, 'repeat_every_Nbar', None)
repeat_every_Nmin = safe_get(options, 'repeat_every_Nmin', None)
#stavové promenne v ramci indikatoru last_run_time a last_run_index - pro repeat_every.. direktivy
last_run_time = safe_get(options, 'last_run_time', None)
last_run_index = safe_get(options, 'last_run_index', None)
#confirmed
cond = on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1)
if cond is False:
return cond, "not confirmed"
#start_at_time - v rámci optimalizace presunout do INIT parametru indikátorů, které se naplní v initu a celou dobu se nemění
if start_at_time is not None:
dt_now = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
# Parse the maxTime string into a datetime object with the same date as timeA
req_start_time = datetime.strptime(start_at_time, "%H:%M").replace(
year=dt_now.year, month=dt_now.month, day=dt_now.day)
# Compare the time components (hours and minutes) of timeA and maxTime
if dt_now.time() > req_start_time.time():
state.ilog(e=f"IND {name} {subtype} START FROM TIME - PASSED: now:{dt_now.time()} reqtime:{req_start_time.time()}")
else:
state.ilog(e=f"IND {name} {subtype} START FROM TIME - NOT YET: now:{dt_now.time()} reqtime:{req_start_time.time()}")
cond = False
if cond is False:
return cond, "start_at_time not yet"
#start_on_bar = 0
if start_at_bar_index is not None:
cond = start_at_bar_index < data["index"]
if cond:
state.ilog(e=f"IND {name} {subtype} START FROM BAR - PASSED: now:{data['index']} reqbar:{start_at_bar_index}")
else:
state.ilog(e=f"IND {name} {subtype} START FROM BAR - NOT YET: now:{data['index']} reqbar:{start_at_bar_index}")
if cond is False:
return cond, "start_at_bar_index not yet"
#pokud 0 - opakujeme jednou, pokud 1 tak opakujeme vzdy, jinak dle poctu
if repeat_every_Nbar is not None:
#jiz bezelo - delame dalsi checky, pokud nebezelo, poustime jako true
if last_run_index is not None:
required_bar_to_run = last_run_index + repeat_every_Nbar
if repeat_every_Nbar == 0:
state.ilog(e=f"IND {name} {subtype} RUN ONCE ALREADY at:{last_run_index} at:{last_run_time}", repeat_every_Nbar=repeat_every_Nbar, last_run_index=last_run_index)
cond = False
elif repeat_every_Nbar == 1:
pass
elif data["index"] < required_bar_to_run:
state.ilog(e=f"IND {name} {subtype} REPEAT EVERY N BAR WAITING: req:{required_bar_to_run} now:{data['index']}", repeat_every_Nbar=repeat_every_Nbar, last_run_index=last_run_index)
cond = False
if cond is False:
return cond, "repeat_every_Nbar not yet"
#pokud nepozadovano, pak poustime
if repeat_every_Nmin is not None:
#porovnavame jen pokud uz bezelo
if last_run_time is not None:
required_time_to_run = last_run_time + timedelta(minutes=repeat_every_Nmin)
datetime_now = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
if datetime_now < required_time_to_run:
state.ilog(e=f"IND {name} {subtype} REPEAT EVERY {repeat_every_Nmin}MINS WAITING", last_run_time=last_run_time, required_time_to_run=required_time_to_run, datetime_now=datetime_now)
cond = False
if cond is False:
return cond, "repeat_every_Nmin not yet"
return cond, "ok"
#testing custom indicator CODE
#TODO customer params bud implicitne **params nebo jako dict
# return 0, new_val or -2, "err msg"
def opengap(params):
funcName = "opengap"
param1 = safe_get(params, "param1")
param2 = safe_get(params, "param2")
state.ilog(e=f"INSIDE {funcName} {param1=} {param2=}", **params)
return 0, random.randint(10, 20)
should_run, msg = is_time_to_run()
if should_run:
#TODO get custom params
custom_params = safe_get(options, "cp", None)
#vyplnime last_run_time a last_run_index
state.vars.indicators[name]["last_run_time"] = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
state.vars.indicators[name]["last_run_index"] = data["index"]
# - volame custom funkci pro ziskani hodnoty indikatoru
# - tu ulozime jako novou hodnotu indikatoru a prepocteme MAcka pokud je pozadovane
# - pokud cas neni, nechavame puvodni, vcetna pripadneho MAcka
#pozor jako defaultní hodnotu dává engine 0 - je to ok?
try:
custom_function = eval(subtype)
res_code, new_val = custom_function(custom_params)
if res_code == 0:
state.indicators[name][-1]=new_val
state.ilog(e=f"IND {name} {subtype} VAL FROM FUNCTION: {new_val}", lastruntime=state.vars.indicators[name]["last_run_time"], lastrunindex=state.vars.indicators[name]["last_run_index"])
#prepocitame MA if required
if MA_length is not None:
src = state.indicators[name][-MA_length:]
MA_res = ema(src, MA_length)
MA_value = round(MA_res[-1],4)
state.indicators[name+"MA"][-1]=MA_value
state.ilog(e=f"IND {name}MA {subtype} {MA_value}")
else:
raise ValueError(f"IND ERROR {name} {subtype}Funkce {custom_function} vratila {res_code} {new_val}.")
except Exception as e:
if len(state.indicators[name]) >= 2:
state.indicators[name][-1]=state.indicators[name][-2]
if MA_length is not None and len(state.indicators[name+"MA"]):
state.indicators[name+"MA"][-1]=state.indicators[name+"MA"][-2]
state.ilog(e=f"IND ERROR {name} {subtype} necháváme původní", message=str(e)+format_exc())
else:
state.ilog(e=f"IND {name} {subtype} COND NOT READY: {msg}")
#not time to run
if len(state.indicators[name]) >= 2:
state.indicators[name][-1]=state.indicators[name][-2]
if MA_length is not None and len(state.indicators[name+"MA"]):
state.indicators[name+"MA"][-1]=state.indicators[name+"MA"][-2]
state.ilog(e=f"IND {name} {subtype} NOT TIME TO RUN - value(and MA) still original")
#EMA INDICATOR
# type = EMA, source = [close, vwap, hlcc4], length = [14], on_confirmed_only = [true, false]
def populate_dynamic_ema_indicator(name):
@ -502,12 +668,24 @@ def next(data, state: StrategyState):
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
try:
#slow_slope = 99
slope_lookback = safe_get(options, 'slope_lookback', 100)
lookback_priceline = safe_get(options, 'lookback_priceline', None)
lookback_offset = safe_get(options, 'lookback_offset', 25)
minimum_slope = safe_get(options, 'minimum_slope', 25)
maximum_slope = safe_get(options, "maximum_slope",0.9)
lookback_offset = safe_get(options, 'lookback_offset', 25)
#jako levy body pouzivame lookback_priceline INDIKATOR vzdaleny slope_lookback barů
if lookback_priceline is not None:
try:
lookbackprice = state.indicators[lookback_priceline][-slope_lookback-1]
lookbacktime = state.bars.updated[-slope_lookback-1]
except IndexError:
max_delka = len(state.indicators[lookback_priceline])
lookbackprice = state.indicators[lookback_priceline][-max_delka]
lookbacktime = state.bars.updated[-max_delka]
else:
#NEMAME LOOKBACK PRICLINE - pouzivame stary způsob výpočtu, toto pozdeji decomissionovat
#lookback has to be even
if lookback_offset % 2 != 0:
lookback_offset += 1
@ -577,7 +755,9 @@ def next(data, state: StrategyState):
state.indicators[name+"MA"][-1]=slopeMA
last_slopesMA = state.indicators[name+"MA"][-10:]
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)
lb_priceline_string = "from "+lookback_priceline if lookback_priceline is not None else ""
state.ilog(e=f"IND {name} {lb_priceline_string} {slope=} {slopeMA=}", msg=f"{lookbackprice=} {lookbacktime=}", lookback_priceline=lookback_priceline, lookbackprice=lookbackprice, lookbacktime=lookbacktime, slope_lookback=slope_lookback, lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators[name][-10:], last_slopesMA=last_slopesMA)
#dale pracujeme s timto MAckovanym slope
#slope = slopeMA
@ -764,7 +944,91 @@ def next(data, state: StrategyState):
return price2dec(float(state.avgp)+normalized_max_profit,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-normalized_max_profit,3)
#TBD pripadne opet dat parsovani pole do INITu
def reverse_conditions_met(direction: TradeDirection):
if direction == TradeDirection.LONG:
smer = "long"
else:
smer = "short"
directive_name = "exit_cond_only_on_confirmed"
exit_cond_only_on_confirmed = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
if exit_cond_only_on_confirmed and data['confirmed'] == 0:
state.ilog("REVERSAL CHECK COND ONLY ON CONFIRMED BAR")
return False
#TOTO zatim u REVERSU neresime
# #POKUD je nastaven MIN PROFIT, zkontrolujeme ho a az pripadne pustime CONDITIONY
# directive_name = "exit_cond_min_profit"
# exit_cond_min_profit = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, None))
# #máme nastavený exit_cond_min_profit
# # zjistíme, zda jsme v daném profit a případně nepustíme dál
# # , zjistíme aktuální cenu a přičteme k avgp tento profit a podle toho pustime dal
# if exit_cond_min_profit is not None:
# exit_cond_min_profit_normalized = normalize_tick(float(exit_cond_min_profit))
# exit_cond_goal_price = price2dec(float(state.avgp)+exit_cond_min_profit_normalized,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-exit_cond_min_profit_normalized,3)
# curr_price = float(data["close"])
# state.ilog(e=f"EXIT COND min profit {exit_cond_goal_price=} {exit_cond_min_profit=} {exit_cond_min_profit_normalized=} {curr_price=}")
# if (int(state.positions) < 0 and curr_price<=exit_cond_goal_price) or (int(state.positions) > 0 and curr_price>=exit_cond_goal_price):
# state.ilog(e=f"EXIT COND min profit PASS - POKRACUJEME")
# else:
# state.ilog(e=f"EXIT COND min profit NOT PASS")
# return False
#TOTO ZATIM NEMA VYZNAM
# options = safe_get(state.vars, 'exit_conditions', None)
# if options is None:
# state.ilog(e="No options for exit conditions in stratvars")
# return False
# disable_exit_proteciton_when = dict(AND=dict(), OR=dict())
# #preconditions
# disable_exit_proteciton_when['disabled_in_config'] = safe_get(options, 'enabled', False) is False
# #too good to be true (maximum profit)
# #disable_sell_proteciton_when['tgtbt_reached'] = safe_get(options, 'tgtbt', False) is False
# disable_exit_proteciton_when['disable_if_positions_above'] = int(safe_get(options, 'disable_if_positions_above', 0)) < abs(int(state.positions))
# #testing preconditions
# result, conditions_met = eval_cond_dict(disable_exit_proteciton_when)
# if result:
# state.ilog(e=f"EXIT_CONDITION for{smer} DISABLED by {conditions_met}", **conditions_met)
# return False
#bereme bud exit condition signalu, ktery activeTrade vygeneroval+ fallback na general
state.ilog(e=f"REVERSE CONDITIONS ENTRY {smer}", conditions=state.vars.conditions[KW.reverse])
mother_signal = state.vars.activeTrade.generated_by
if mother_signal is not None:
cond_dict = state.vars.conditions[KW.reverse][state.vars.activeTrade.generated_by][smer]
result, conditions_met = evaluate_directive_conditions(cond_dict, "OR")
state.ilog(e=f"REVERSE CONDITIONS of {mother_signal} =OR= {result}", **conditions_met, cond_dict=cond_dict)
if result:
return True
#OR neprosly testujeme AND
result, conditions_met = evaluate_directive_conditions(cond_dict, "AND")
state.ilog(e=f"REVERSE CONDITIONS of {mother_signal} =AND= {result}", **conditions_met, cond_dict=cond_dict)
if result:
return True
#pokud nemame mother signal nebo exit nevratil nic, fallback na common
cond_dict = state.vars.conditions[KW.reverse]["common"][smer]
result, conditions_met = evaluate_directive_conditions(cond_dict, "OR")
state.ilog(e=f"REVERSE CONDITIONS of COMMON =OR= {result}", **conditions_met, cond_dict=cond_dict)
if result:
return True
#OR neprosly testujeme AND
result, conditions_met = evaluate_directive_conditions(cond_dict, "AND")
state.ilog(e=f"REVERSE CONDITIONS of COMMON =AND= {result}", **conditions_met, cond_dict=cond_dict)
if result:
return True
def exit_conditions_met(direction: TradeDirection):
if direction == TradeDirection.LONG:
@ -945,8 +1209,9 @@ def next(data, state: StrategyState):
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)
def close_position(direction: TradeDirection, reason: str, reverse: bool = False):
reversal_text = "REVERSAL" if reverse else ""
state.ilog(e=f"CLOSING TRADE {reversal_text} {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:
@ -965,6 +1230,8 @@ def next(data, state: StrategyState):
state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None
state.vars.last_exit_index = data["index"]
if reverse:
state.vars.reverse_requested = True
def eval_close_position():
curr_price = float(data['close'])
@ -987,12 +1254,24 @@ def next(data, state: StrategyState):
#SL - execution
if curr_price > state.vars.activeTrade.stoploss_value:
close_position(direction=TradeDirection.SHORT, reason="SL REACHED")
directive_name = 'reverse_for_SL_exit_short'
reverse_for_SL_exit = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
close_position(direction=TradeDirection.SHORT, reason="SL REACHED", reverse=reverse_for_SL_exit)
return
#REVERSE BASED ON REVERSE CONDITIONS
if reverse_conditions_met(TradeDirection.SHORT):
close_position(direction=TradeDirection.SHORT, reason="REVERSE COND MET", reverse=True)
return
#CLOSING BASED ON EXIT CONDITIONS
if exit_conditions_met(TradeDirection.SHORT):
close_position(direction=TradeDirection.SHORT, reason="EXIT COND MET")
directive_name = 'reverse_for_cond_exit_short'
reverse_for_cond_exit = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
close_position(direction=TradeDirection.SHORT, reason="EXIT COND MET", reverse=reverse_for_cond_exit)
return
#PROFIT
@ -1011,11 +1290,24 @@ def next(data, state: StrategyState):
#SL - execution
if curr_price < state.vars.activeTrade.stoploss_value:
close_position(direction=TradeDirection.LONG, reason="SL REACHED")
directive_name = 'reverse_for_SL_exit_long'
reverse_for_SL_exit = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
close_position(direction=TradeDirection.LONG, reason="SL REACHED", reverse=reverse_for_SL_exit)
return
#REVERSE BASED ON REVERSE CONDITIONS
if reverse_conditions_met(TradeDirection.LONG):
close_position(direction=TradeDirection.LONG, reason="REVERSE COND MET", reverse=True)
return
#EXIT CONDITIONS
if exit_conditions_met(TradeDirection.LONG):
close_position(direction=TradeDirection.LONG, reason="EXIT CONDS MET")
directive_name = 'reverse_for_cond_exit_long'
reverse_for_cond_exit = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
close_position(direction=TradeDirection.LONG, reason="EXIT CONDS MET", reverse=reverse_for_cond_exit)
return
#PROFIT
@ -1059,7 +1351,11 @@ def next(data, state: StrategyState):
if state.vars.activeTrade:
if state.vars.activeTrade.direction == TradeDirection.LONG:
state.ilog(e="odesilame LONG ORDER", trade=json.loads(json.dumps(state.vars.activeTrade, default=json_serial)))
res = state.buy(size=state.vars.chunk)
if state.vars.activeTrade.size is not None:
size = state.vars.activeTrade.size
else:
size = state.vars.chunk
res = state.buy(size=size)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation LONG {res}")
#pokud neni nastaveno SL v prescribe, tak nastavuji default dle stratvars
@ -1073,7 +1369,11 @@ def next(data, state: StrategyState):
state.vars.pending = state.vars.activeTrade.id
elif state.vars.activeTrade.direction == TradeDirection.SHORT:
state.ilog(e="odesilame SHORT ORDER",trade=json.loads(json.dumps(state.vars.activeTrade, default=json_serial)))
res = state.sell(size=state.vars.chunk)
if state.vars.activeTrade.size is not None:
size = state.vars.activeTrade.size
else:
size = state.vars.chunk
res = state.sell(size=size)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation SHORT {res}")
#pokud neni nastaveno SL v prescribe, tak nastavuji default dle stratvars
@ -1245,11 +1545,19 @@ def next(data, state: StrategyState):
if common_go_preconditions_check(signalname=name, options=options) is False:
return
plugin = safe_get(options, 'plugin', None)
# signal_plugin = "reverzni"
# signal_plugin_run_once_at_index = 3
#pokud existuje plugin, tak pro signal search volame plugin a ignorujeme conditiony
signal_plugin = safe_get(options, 'plugin', None)
signal_plugin_run_once_at_index = safe_get(options, 'signal_plugin_run_once_at_index', 3)
#pokud je plugin True, spusti se kod
if plugin:
execute_signal_generator_plugin(name)
if signal_plugin is not None and signal_plugin_run_once_at_index==data["index"]:
try:
custom_function = eval(signal_plugin)
custom_function()
except NameError:
state.ilog(e="Custom plugin {signal_plugin} not found")
else:
short_enabled = safe_get(options, "short_enabled",safe_get(state.vars, "short_enabled",True))
long_enabled = safe_get(options, "long_enabled",safe_get(state.vars, "long_enabled",True))
@ -1431,6 +1739,7 @@ def init(state: StrategyState):
state.vars.conditions.setdefault(KW.dont_go,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.dont_go+"_" + smer +"_if", section=section)
state.vars.conditions.setdefault(KW.go,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.go+"_" + smer +"_if", section=section)
state.vars.conditions.setdefault(KW.exit,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.exit+"_" + smer +"_if", section=section)
state.vars.conditions.setdefault(KW.reverse,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.reverse+"_" + smer +"_if", section=section)
# 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")
@ -1439,6 +1748,7 @@ def init(state: StrategyState):
section = state.vars.exit["conditions"]
for smer in TradeDirection:
state.vars.conditions.setdefault(KW.exit,{}).setdefault("common",{})[smer] = get_conditions_from_configuration(action=KW.exit+"_" + smer +"_if", section=section)
state.vars.conditions.setdefault(KW.reverse,{}).setdefault("common",{})[smer] = get_conditions_from_configuration(action=KW.reverse+"_" + smer +"_if", section=section)
#init klice v extData pro ulozeni historie SL
state.extData["sl_history"] = []
@ -1450,6 +1760,8 @@ def init(state: StrategyState):
state.vars.activeTrade = None #pending/Trade
#obsahuje pripravene Trady ve frontě
state.vars.prescribedTrades = []
#flag pro reversal
state.vars.reverse_requested = False
#TODO presunout inicializaci work_dict u podminek - sice hodnoty nepujdou zmenit, ale zlepsi se performance
#pripadne udelat refresh kazdych x-iterací

View File

@ -23,6 +23,7 @@ class Trade(BaseModel):
generated_by: Optional[str] = None
direction: TradeDirection
entry_price: Optional[float] = None
size: Optional[int] = None
# stoploss_type: TradeStoplossType
stoploss_value: Optional[float] = None
profit: Optional[float] = 0

View File

@ -103,3 +103,4 @@ class KW:
go: str = "go"
activate: str = "activate"
exit: str = "exit"
reverse: str = "reverse"

View File

@ -573,7 +573,7 @@
<input type="text" id="itemName"><br><br>
<label for="jsonTextarea">JSON Data:</label><br>
<textarea id="jsonTextarea" rows="10" cols="50"></textarea><br><br>
<textarea id="jsonTextarea" rows="15" cols="75"></textarea><br><br>
<button type="button" id="saveButton">Save</button>
<button type="button" id="addButton">Add</button>

View File

@ -38,6 +38,7 @@ $(document).ready(function () {
rows = archiveRecords.rows('.selected').data();
var record1 = new Object()
//console.log(JSON.stringify(rows))
record1 = JSON.parse(rows[0].strat_json)
//record1.json = rows[0].json
//record1.id = rows[0].id;
@ -48,6 +49,8 @@ $(document).ready(function () {
// record1.script = rows[0].script;
// record1.open_rush = rows[0].open_rush;
// record1.close_rush = rows[0].close_rush;
//console.log(record1.stratvars_conf)
record1.stratvars_conf = TOML.parse(record1.stratvars_conf);
record1.add_data_conf = TOML.parse(record1.add_data_conf);
// record1.note = rows[0].note;
@ -65,6 +68,7 @@ $(document).ready(function () {
// record2.script = rows[1].script;
// record2.open_rush = rows[1].open_rush;
// record2.close_rush = rows[1].close_rush;
record2.stratvars_conf = TOML.parse(record2.stratvars_conf);
record2.add_data_conf = TOML.parse(record2.add_data_conf);
// record2.note = rows[1].note;

View File

@ -356,6 +356,7 @@ pre {
display: flex;
align-items: center;
margin-left: 54px;
width: 323px;
height: 30px;
margin-top: 8px;
color: #2196F3;

View File

@ -4,6 +4,7 @@ from v2realbot.utils.tlog import tlog, tlog_exception
from v2realbot.enums.enums import Mode, Order, Account, RecordType
#from alpaca.trading.models import TradeUpdate
from v2realbot.common.model import TradeUpdate
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
from alpaca.trading.enums import TradeEvent, OrderStatus
from v2realbot.indicators.indicators import ema
import json
@ -13,7 +14,7 @@ from random import randrange
from alpaca.common.exceptions import APIError
import copy
from threading import Event
from uuid import UUID
from uuid import UUID, uuid4
class StrategyClassicSL(Strategy):
@ -42,13 +43,30 @@ class StrategyClassicSL(Strategy):
send_to_telegram(f"QUITTING MAX SUM LOSS REACHED {max_sum_loss_to_quit=} {self.state.profit=}")
self.se.set()
async def add_reversal(self, direction: TradeDirection, size: int, signal_name: str):
trade_to_add = Trade(
id=uuid4(),
last_update=datetime.fromtimestamp(self.state.time).astimezone(zoneNY),
status=TradeStatus.READY,
size=size,
generated_by=signal_name,
direction=direction,
entry_price=None,
stoploss_value = None)
self.state.vars.prescribedTrades.append(trade_to_add)
self.state.vars.reverse_requested = None
self.state.ilog(e=f"REVERZAL {direction} added to prescr.trades {signal_name=} {size=}", trade=trade_to_add)
async def orderUpdateBuy(self, data: TradeUpdate):
o: Order = data.order
signal_name = None
##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 data.event == TradeEvent.FILL or data.event == TradeEvent.PARTIAL_FILL:
#jde o uzavření short pozice - počítáme PROFIT
@ -86,6 +104,11 @@ class StrategyClassicSL(Strategy):
#test na maximalni profit/loss
await self.check_max_profit_loss()
#pIF REVERSAL REQUIRED - reverse position is added to prescr.Trades with same signal name
#jen při celém FILLU
if data.event == TradeEvent.FILL and self.state.vars.reverse_requested:
await self.add_reversal(direction=TradeDirection.LONG, size=data.qty, signal_name=signal_name)
else:
#zjistime nazev signalu a updatneme do tradeListu - abychom meli svazano
for trade in self.state.vars.prescribedTrades:
@ -109,6 +132,7 @@ class StrategyClassicSL(Strategy):
#davame pryc pending
self.state.vars.pending = None
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)))
@ -148,6 +172,10 @@ class StrategyClassicSL(Strategy):
await self.check_max_profit_loss()
#IF REVERSAL REQUIRED - reverse position is added to prescr.Trades with same signal name
if data.event == TradeEvent.FILL and self.state.vars.reverse_requested:
await self.add_reversal(direction=TradeDirection.SHORT, size=data.qty, signal_name=signal_name)
else:
#zjistime nazev signalu a updatneme do tradeListu - abychom meli svazano
for trade in self.state.vars.prescribedTrades: