pridano indikator natr + vychytavky na frontendu

This commit is contained in:
David Brazda
2023-09-06 17:37:56 +02:00
parent 073b19edfd
commit e08ae0f537
7 changed files with 88 additions and 21 deletions

View File

@ -3,7 +3,7 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.strategy.base import StrategyState from v2realbot.strategy.base import StrategyState
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
from v2realbot.indicators.indicators import ema from v2realbot.indicators.indicators import ema, natr
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, is_still, is_window_open, 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, is_still, is_window_open, eval_cond_dict, Average, crossed_down, crossed_up, crossed, is_pivot, json_serial
@ -248,6 +248,8 @@ def next(data, state: StrategyState):
populate_dynamic_RSI_indicator(name = name) populate_dynamic_RSI_indicator(name = name)
elif type == "EMA": elif type == "EMA":
populate_dynamic_ema_indicator(name = name) populate_dynamic_ema_indicator(name = name)
elif type == "NATR":
populate_dynamic_natr_indicator(name = name)
else: else:
return return
@ -285,6 +287,34 @@ def next(data, state: StrategyState):
except Exception as e: except Exception as e:
state.ilog(e=f"IND ERROR {name} EMA necháváme 0", message=str(e)+format_exc()) state.ilog(e=f"IND ERROR {name} EMA necháváme 0", message=str(e)+format_exc())
#NATR INDICATOR
# type = NATR, ĺength = [14], on_confirmed_only = [true, false]
def populate_dynamic_natr_indicator(name):
ind_type = "NATR"
options = safe_get(state.vars.indicators, name, None)
if options is None:
state.ilog(e=f"No options for {name} in stratvars")
return
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
natr_length = int(safe_get(options, "length",5))
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
try:
source_high = state.bars["high"][-natr_length:]
source_low = state.bars["low"][-natr_length:]
source_close = state.bars["close"][-natr_length:]
#if len(source) > ema_length:
natr_value = natr(source_high, source_low, source_close, natr_length)
val = round(natr_value[-1],4)
state.indicators[name][-1]= val
#state.indicators[name][-1]= round2five(val)
state.ilog(e=f"IND {name} NATR {val} {natr_length=}")
#else:
# state.ilog(e=f"IND {name} EMA necháváme 0", message="not enough source data", source=source, ema_length=ema_length)
except Exception as e:
state.ilog(e=f"IND ERROR {name} NATR necháváme 0", message=str(e)+format_exc())
#RSI INDICATOR #RSI INDICATOR
# type = RSI, source = [close, vwap, hlcc4], rsi_length = [14], MA_length = int (optional), on_confirmed_only = [true, false] # type = RSI, source = [close, vwap, hlcc4], rsi_length = [14], MA_length = int (optional), on_confirmed_only = [true, false]
# pokud existuje MA, vytvarime i stejnojnojmenny MAcko # pokud existuje MA, vytvarime i stejnojnojmenny MAcko
@ -742,18 +772,32 @@ def next(data, state: StrategyState):
else: else:
smer = "short" smer = "short"
#get name of strategy directive_name = "exit_cond_only_on_confirmed"
signal_originator = state.vars.activeTrade.generated_by exit_cond_only_on_confirmed = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
if signal_originator is not None:
exit_cond_only_on_confirmed = safe_get(state.vars.signals[signal_originator], "exit_cond_only_on_confirmed", safe_get(state.vars, "exit_cond_only_on_confirmed", False))
else:
exit_cond_only_on_confirmed = safe_get(state.vars, "exit_cond_only_on_confirmed", False)
if exit_cond_only_on_confirmed and data['confirmed'] == 0: if exit_cond_only_on_confirmed and data['confirmed'] == 0:
state.ilog("EXIT COND ONLY ON CONFIRMED BAR") state.ilog("EXIT COND ONLY ON CONFIRMED BAR")
return False return False
#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 #TOTO ZATIM NEMA VYZNAM
# options = safe_get(state.vars, 'exit_conditions', None) # options = safe_get(state.vars, 'exit_conditions', None)
# if options is None: # if options is None:
@ -920,6 +964,7 @@ def next(data, state: StrategyState):
insert_SL_history() insert_SL_history()
state.vars.pending = state.vars.activeTrade.id state.vars.pending = state.vars.activeTrade.id
state.vars.activeTrade = None state.vars.activeTrade = None
state.vars.last_exit_index = data["index"]
def eval_close_position(): def eval_close_position():
curr_price = float(data['close']) curr_price = float(data['close'])
@ -1125,14 +1170,6 @@ def next(data, state: StrategyState):
#ZAKLADNI KONTROLY ATRIBUTU s fallbackem na obecné #ZAKLADNI KONTROLY ATRIBUTU s fallbackem na obecné
#check working windows (open - close, in minutes from the start of marker) #check working windows (open - close, in minutes from the start of marker)
next_signal_offset = safe_get(options, "next_signal_offset_from_last",safe_get(state.vars, "next_signal_offset_from_last",0))
if state.vars.last_buy_index is not None:
index_to_compare = int(state.vars.last_buy_index)+int(next_signal_offset)
if index_to_compare > int(data["index"]):
state.ilog(e=f"NEXT SIGNAL OFFSET {next_signal_offset} waiting - TOO SOON", currindex=data["index"], index_to_compare=index_to_compare)
return False
window_open = safe_get(options, "window_open",safe_get(state.vars, "window_open",0)) window_open = safe_get(options, "window_open",safe_get(state.vars, "window_open",0))
window_close = safe_get(options, "window_close",safe_get(state.vars, "window_close",390)) window_close = safe_get(options, "window_close",safe_get(state.vars, "window_close",390))
@ -1140,6 +1177,14 @@ def next(data, state: StrategyState):
state.ilog(e=f"SIGNAL {signalname} - WINDOW CLOSED", msg=f"{window_open=} {window_close=} ") state.ilog(e=f"SIGNAL {signalname} - WINDOW CLOSED", msg=f"{window_open=} {window_close=} ")
return False return False
next_signal_offset = safe_get(options, "next_signal_offset_from_last_exit",safe_get(state.vars, "next_signal_offset_from_last_exit",0))
if state.vars.last_exit_index is not None:
index_to_compare = int(state.vars.last_exit_index)+int(next_signal_offset)
if index_to_compare > int(data["index"]):
state.ilog(e=f"NEXT SIGNAL OFFSET from EXIT {next_signal_offset} waiting - TOO SOON", currindex=data["index"], index_to_compare=index_to_compare, last_exit_index=state.vars.last_exit_index)
return False
# if is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), open_rush) or is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), close_rush): # 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=f"SIGNAL {signalname} - WINDOW CLOSED", msg=f"{open_rush=} {close_rush=} ") # state.ilog(e=f"SIGNAL {signalname} - WINDOW CLOSED", msg=f"{open_rush=} {close_rush=} ")
# return False # return False
@ -1415,6 +1460,7 @@ def init(state: StrategyState):
state.vars.last_tick_volume = 0 state.vars.last_tick_volume = 0
state.vars.next_new = 0 state.vars.next_new = 0
state.vars.last_buy_index = None state.vars.last_buy_index = None
state.vars.last_exit_index = None
state.vars.last_update_time = 0 state.vars.last_update_time = 0
state.vars.reverse_position_waiting_amount = 0 state.vars.reverse_position_waiting_amount = 0
#INIT promenne, ktere byly zbytecne ve stratvars #INIT promenne, ktere byly zbytecne ve stratvars

View File

@ -121,6 +121,7 @@ class Runner(BaseModel):
run_instance: Optional[object] = None run_instance: Optional[object] = None
run_pause_ev: Optional[object] = None run_pause_ev: Optional[object] = None
run_stop_ev: Optional[object] = None run_stop_ev: Optional[object] = None
run_stratvars_toml: Optional[str] = None
class Bar(BaseModel): class Bar(BaseModel):
@ -207,6 +208,7 @@ class RunArchive(BaseModel):
end_positions: int = 0 end_positions: int = 0
end_positions_avgp: float = 0 end_positions_avgp: float = 0
open_orders: Union[dict, int] = None open_orders: Union[dict, int] = None
stratvars_toml: Optional[str] = None
#trida pro ukladani historie stoplossy do ext_data #trida pro ukladani historie stoplossy do ext_data
class SLHistory(BaseModel): class SLHistory(BaseModel):

View File

@ -490,7 +490,8 @@ def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False, inter_b
run_account = runReq.account, run_account = runReq.account,
run_ilog_save = runReq.ilog_save, run_ilog_save = runReq.ilog_save,
run_mode = runReq.mode, run_mode = runReq.mode,
run_instance = instance) run_instance = instance,
run_stratvars_toml=i.stratvars_conf)
db.runners.append(runner) db.runners.append(runner)
print(db.runners) print(db.runners)
print(i) print(i)
@ -666,7 +667,8 @@ def archive_runner(runner: Runner, strat: StrategyInstance, inter_batch_params:
trade_count=len(strat.state.tradeList), trade_count=len(strat.state.tradeList),
end_positions=strat.state.positions, end_positions=strat.state.positions,
end_positions_avgp=round(float(strat.state.avgp),3), end_positions_avgp=round(float(strat.state.avgp),3),
open_orders=results_metrics open_orders=results_metrics,
stratvars_toml=runner.run_stratvars_toml
) )
#flatten indicators from numpy array #flatten indicators from numpy array

View File

@ -5,6 +5,14 @@ from collections import deque
import typing import typing
from v2realbot.utils.utils import check_series, convert_to_numpy from v2realbot.utils.utils import check_series, convert_to_numpy
def natr(data_high, data_low, data_close, period: int = 5):
data_high = convert_to_numpy(data_high)
data_low = convert_to_numpy(data_low)
data_close = convert_to_numpy(data_close)
natr = ti.natr(data_high, data_low, data_close, period=period)
return natr
def ema(data, period: int = 50, use_series=False): def ema(data, period: int = 50, use_series=False):
if check_series(data): if check_series(data):
use_series = True use_series = True

View File

@ -100,7 +100,15 @@ $(document).ready(function () {
$('#editidarchive').val(row.id); $('#editidarchive').val(row.id);
$('#editnote').val(row.note); $('#editnote').val(row.note);
$('#metrics').val(JSON.stringify(row.open_orders,null,2)); $('#metrics').val(JSON.stringify(row.open_orders,null,2));
//$('#metrics').val(TOML.parse(row.open_orders));
if (row.stratvars_toml) {
$('#editstratvars').val(row.stratvars_toml);
}
else{
$('#editstratvars').val(JSON.stringify(row.stratvars,null,2)); $('#editstratvars').val(JSON.stringify(row.stratvars,null,2));
}
$('#editstratjson').val(row.strat_json); $('#editstratjson').val(row.strat_json);
}); });
@ -237,7 +245,8 @@ var archiveRecords =
{data: 'end_positions', visible: true}, {data: 'end_positions', visible: true},
{data: 'end_positions_avgp', visible: true}, {data: 'end_positions_avgp', visible: true},
{data: 'strat_json', visible: false}, {data: 'strat_json', visible: false},
{data: 'open_orders', visible: true} {data: 'open_orders', visible: true},
{data: 'stratvars_toml', visible: false},
], ],
paging: false, paging: false,
processing: false, processing: false,