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.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
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.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
@ -248,6 +248,8 @@ def next(data, state: StrategyState):
populate_dynamic_RSI_indicator(name = name)
elif type == "EMA":
populate_dynamic_ema_indicator(name = name)
elif type == "NATR":
populate_dynamic_natr_indicator(name = name)
else:
return
@ -285,6 +287,34 @@ def next(data, state: StrategyState):
except Exception as e:
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
# 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
@ -742,18 +772,32 @@ def next(data, state: StrategyState):
else:
smer = "short"
#get name of strategy
signal_originator = state.vars.activeTrade.generated_by
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)
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("EXIT COND ONLY ON CONFIRMED BAR")
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
# options = safe_get(state.vars, 'exit_conditions', None)
# if options is None:
@ -919,7 +963,8 @@ def next(data, state: StrategyState):
#pri uzavreni tradu zapisujeme SL history - lepsi zorbazeni v grafu
insert_SL_history()
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():
curr_price = float(data['close'])
@ -1125,14 +1170,6 @@ def next(data, state: StrategyState):
#ZAKLADNI KONTROLY ATRIBUTU s fallbackem na obecné
#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_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=} ")
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):
# state.ilog(e=f"SIGNAL {signalname} - WINDOW CLOSED", msg=f"{open_rush=} {close_rush=} ")
# return False
@ -1415,6 +1460,7 @@ def init(state: StrategyState):
state.vars.last_tick_volume = 0
state.vars.next_new = 0
state.vars.last_buy_index = None
state.vars.last_exit_index = None
state.vars.last_update_time = 0
state.vars.reverse_position_waiting_amount = 0
#INIT promenne, ktere byly zbytecne ve stratvars

View File

@ -121,6 +121,7 @@ class Runner(BaseModel):
run_instance: Optional[object] = None
run_pause_ev: Optional[object] = None
run_stop_ev: Optional[object] = None
run_stratvars_toml: Optional[str] = None
class Bar(BaseModel):
@ -207,6 +208,7 @@ class RunArchive(BaseModel):
end_positions: int = 0
end_positions_avgp: float = 0
open_orders: Union[dict, int] = None
stratvars_toml: Optional[str] = None
#trida pro ukladani historie stoplossy do ext_data
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_ilog_save = runReq.ilog_save,
run_mode = runReq.mode,
run_instance = instance)
run_instance = instance,
run_stratvars_toml=i.stratvars_conf)
db.runners.append(runner)
print(db.runners)
print(i)
@ -666,7 +667,8 @@ def archive_runner(runner: Runner, strat: StrategyInstance, inter_batch_params:
trade_count=len(strat.state.tradeList),
end_positions=strat.state.positions,
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

View File

@ -5,6 +5,14 @@ from collections import deque
import typing
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):
if check_series(data):
use_series = True

View File

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