From dc4d0b86018496a76f570d1294d3ce5cb716fade Mon Sep 17 00:00:00 2001 From: David Brazda Date: Sun, 17 Sep 2023 11:22:40 +0200 Subject: [PATCH] na FE: runagain button + compare profits func --- v2realbot/ENTRY_ClassicSL_v01.py | 20 ++- .../common/__pycache__/model.cpython-310.pyc | Bin 7633 -> 7633 bytes v2realbot/common/model.py | 2 +- v2realbot/controller/services.py | 27 ++-- v2realbot/static/index.html | 1 + v2realbot/static/js/archivetables.js | 143 +++++++++++++++++- 6 files changed, 177 insertions(+), 16 deletions(-) diff --git a/v2realbot/ENTRY_ClassicSL_v01.py b/v2realbot/ENTRY_ClassicSL_v01.py index 3c2ee0a..77f72ff 100644 --- a/v2realbot/ENTRY_ClassicSL_v01.py +++ b/v2realbot/ENTRY_ClassicSL_v01.py @@ -426,7 +426,25 @@ def next(data, state: StrategyState): elif mode == "pct": val = pct_diff(num1=float(source1_series[-1]),num2=float(source2_series[-1])) return 0, val - + + #strength, absolute change of parameter between current value and lookback value (n-past) + #used for example to measure unusual peaks + def delta(params): + funcName = "delta" + source = safe_get(params, "source", None) + lookback = safe_get(params, "lookback",1) + if source in ["open","high","low","close","vwap","hlcc4"]: + source_series = state.bars[source] + else: + source_series = state.indicators[source] + + lookbackval = source_series[-lookback-1] + currval = source_series[-1] + delta = currval - lookbackval + + state.ilog(lvl=1,e=f"INSIDE {funcName} {delta} {source=} {lookback=}", currval=currval, lookbackval=lookbackval, **params) + return 0, delta + #rate of change - last value of source indicator vs lookback value of lookback_priceline indicator def slope(params): funcName = "slope" diff --git a/v2realbot/common/__pycache__/model.cpython-310.pyc b/v2realbot/common/__pycache__/model.cpython-310.pyc index 22c4329be12a0078e47cfca50ad19ea9688c4fbb..0f24decb19329293662e47cb121f8fceffc75b5d 100644 GIT binary patch delta 28 icmca;ebJgHpO=@50SLJEv!!n2*&)Hmy7{OC4=Vs{xCbBr delta 28 icmca;ebJgHpO=@50SL~{`jN7cXNLr%_~xS$JgfkM$q2y! diff --git a/v2realbot/common/model.py b/v2realbot/common/model.py index e2987bb..e333109 100644 --- a/v2realbot/common/model.py +++ b/v2realbot/common/model.py @@ -207,7 +207,7 @@ class RunArchive(BaseModel): trade_count: int = 0 end_positions: int = 0 end_positions_avgp: float = 0 - open_orders: Union[dict, int] = None + open_orders: Union[dict, str] = None stratvars_toml: Optional[str] = None #trida pro ukladani historie stoplossy do ext_data diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index 89403e9..c0c9058 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -564,12 +564,13 @@ def populate_metrics_output_directory(strat: StrategyInstance, inter_batch_param max_positions = max_positions[max_positions['side'] == OrderSide.SELL] max_positions = max_positions.drop(columns=['side'], axis=1) + res = dict(profit={}) #filt = max_positions['side'] == 'OrderSide.BUY' - res = dict(zip(max_positions['qty'], max_positions['count'])) + res["pos_cnt"] = dict(zip(max_positions['qty'], max_positions['count'])) #naplneni batch sum profitu if inter_batch_params is not None: - res["batch_sum_profit"] = inter_batch_params["batch_profit"] + res["profit"]["batch_sum_profit"] = inter_batch_params["batch_profit"] #metrikz z prescribedTrades, pokud existuji try: @@ -603,16 +604,16 @@ def populate_metrics_output_directory(strat: StrategyInstance, inter_batch_param short_losses += trade.profit if trade.profit > 0: short_wins += trade.profit - res["long_cnt"] = long_cnt - res["short_cnt"] = short_cnt - res["long_profit"] = round(long_profit,2) - res["short_profit"] = round(short_profit,2) - res["long_losses"] = round(long_losses,2) - res["short_losses"] = round(short_losses,2) - res["long_wins"] = round(long_wins,2) - res["short_wins"] = round(short_wins,2) - res["max_profit"] = round(max_profit,2) - res["max_profit_time"] = str(max_profit_time) + res["profit"]["long_cnt"] = long_cnt + res["profit"]["short_cnt"] = short_cnt + res["profit"]["long_profit"] = round(long_profit,2) + res["profit"]["short_profit"] = round(short_profit,2) + res["profit"]["long_losses"] = round(long_losses,2) + res["profit"]["short_losses"] = round(short_losses,2) + res["profit"]["long_wins"] = round(long_wins,2) + res["profit"]["short_wins"] = round(short_wins,2) + res["profit"]["max_profit"] = round(max_profit,2) + res["profit"]["max_profit_time"] = str(max_profit_time) #vlozeni celeho listu res["prescr_trades"]=json.loads(json.dumps(strat.state.vars.prescribedTrades, default=json_serial)) @@ -673,7 +674,7 @@ 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=json.dumps(results_metrics, default=json_serial), stratvars_toml=runner.run_stratvars_toml ) diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index 659e374..3515627 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -181,6 +181,7 @@ + diff --git a/v2realbot/static/js/archivetables.js b/v2realbot/static/js/archivetables.js index 2eec0dd..c381746 100644 --- a/v2realbot/static/js/archivetables.js +++ b/v2realbot/static/js/archivetables.js @@ -8,6 +8,7 @@ $(document).ready(function () { }); //disable buttons (enable on row selection) + $('#button_runagain_arch').attr('disabled','disabled'); $('#button_show_arch').attr('disabled','disabled'); $('#button_delete_arch').attr('disabled','disabled'); $('#button_edit_arch').attr('disabled','disabled'); @@ -18,6 +19,7 @@ $(document).ready(function () { if ($(this).hasClass('selected')) { //$(this).removeClass('selected'); $('#button_show_arch').attr('disabled','disabled'); + $('#button_runagain_arch').attr('disabled','disabled'); $('#button_delete_arch').attr('disabled','disabled'); $('#button_edit_arch').attr('disabled','disabled'); $('#button_compare_arch').attr('disabled','disabled'); @@ -25,6 +27,7 @@ $(document).ready(function () { //archiveRecords.$('tr.selected').removeClass('selected'); $(this).addClass('selected'); $('#button_show_arch').attr('disabled',false); + $('#button_runagain_arch').attr('disabled',false); $('#button_delete_arch').attr('disabled',false); $('#button_edit_arch').attr('disabled',false); $('#button_compare_arch').attr('disabled',false); @@ -51,6 +54,18 @@ $(document).ready(function () { // record1.close_rush = rows[0].close_rush; //console.log(record1.stratvars_conf) + //ELEMENTS TO COMPARE + + //profit sekce + console.log(rows[0].open_orders) + + try { + record1["profit"] = JSON.parse(rows[0].open_orders).profit + } + catch (e) { + console.log(e.message) + } + record1.stratvars_conf = TOML.parse(record1.stratvars_conf); record1.add_data_conf = TOML.parse(record1.add_data_conf); // record1.note = rows[0].note; @@ -69,6 +84,15 @@ $(document).ready(function () { // record2.open_rush = rows[1].open_rush; // record2.close_rush = rows[1].close_rush; + //ELEMENTS TO COMPARE + console.log(rows[1].open_orders) + + try { + record2["profit"] = JSON.parse(rows[1].open_orders).profit + } + catch (e) { + console.log(e.message) + } record2.stratvars_conf = TOML.parse(record2.stratvars_conf); record2.add_data_conf = TOML.parse(record2.add_data_conf); // record2.note = rows[1].note; @@ -117,7 +141,15 @@ $(document).ready(function () { window.$('#editModalArchive').modal('show'); $('#editidarchive').val(row.id); $('#editnote').val(row.note); - $('#metrics').val(JSON.stringify(row.open_orders,null,2)); + + + try { + metrics = JSON.parse(row.open_orders) + } + catch (e) { + metrics = row.open_orders + } + $('#metrics').val(JSON.stringify(metrics,null,2)); //$('#metrics').val(TOML.parse(row.open_orders)); if (row.stratvars_toml) { $('#editstratvars').val(row.stratvars_toml); @@ -163,6 +195,108 @@ $(document).ready(function () { }); }) + //run again button + $('#button_runagain_arch').click(function () { + row = archiveRecords.row('.selected').data(); + $('#button_runagain_arch').attr('disabled',true); + + var record1 = new Object() + //console.log(JSON.stringify(rows)) + + //record1 = JSON.parse(rows[0].strat_json) + //record1.json = rows[0].json + + //TBD mozna zkopirovat jen urcite? + record1 = row + console.log(record1) + + //smazeneme nepotrebne a pridame potrebne + //do budoucna predelat na vytvoreni noveho objektu + //nebudeme muset odstanovat pri kazdem pridani noveho atributu v budoucnu + delete record1["end_positions"]; + delete record1["end_positions_avgp"]; + delete record1["profit"]; + delete record1["trade_count"]; + delete record1["stratvars_toml"]; + delete record1["started"]; + delete record1["stopped"]; + delete record1["open_orders"]; + delete record1["settings"]; + delete record1["stratvars"]; + + record1.note = "RERUN " + record1.note + + if (record1.bt_from == "") {delete record1["bt_from"];} + if (record1.bt_to == "") {delete record1["bt_to"];} + + //mazeme, pouze rerunujeme single + record1["test_batch_id"]; + + //najdeme ve stratinu radek s danym ID a z tohoto radku a sestavime strat_json + var idToFind = record1.strat_id; // Replace with the specific ID you want to find + + var foundRow = stratinRecords.rows().eq(0).filter(function (rowIdx) { + return stratinRecords.row(rowIdx).data().id === idToFind; + }); + + if (foundRow.length > 0) { + // Get the data of the first matching row + var stratData = stratinRecords.row(foundRow[0]).data(); + console.log(stratData); + } else { + // Handle the case where no matching row is found + console.log("No strategy with ID " + idToFind + " found."); + window.alert("No strategy with ID " + idToFind + " found.") + return + } + + const rec = new Object() + rec.id2 = parseInt(stratData.id2); + rec.name = stratData.name; + rec.symbol = stratData.symbol; + rec.class_name = stratData.class_name; + rec.script = stratData.script; + rec.open_rush = stratData.open_rush; + rec.close_rush = stratData.close_rush; + rec.stratvars_conf = stratData.stratvars_conf; + rec.add_data_conf = stratData.add_data_conf; + rec.note = stratData.note; + rec.history = ""; + strat_json = JSON.stringify(rec, null, 2); + record1.strat_json = strat_json + + //zkopirujeme strat_id do id a smazeme strat_id + record1.id = record1.strat_id + delete record1["strat_id"]; + + console.log("record1 pred odeslanim", record1) + jsonString = JSON.stringify(record1); + + $.ajax({ + url:"/stratins/"+record1.id+"/run", + beforeSend: function (xhr) { + xhr.setRequestHeader('X-API-Key', + API_KEY); }, + method:"PUT", + contentType: "application/json", + data: jsonString, + success:function(data){ + $('#button_runagain_arch').attr('disabled',false); + setTimeout(function () { + runnerRecords.ajax.reload(); + stratinRecords.ajax.reload(); + }, 1500); + }, + error: function(xhr, status, error) { + var err = eval("(" + xhr.responseText + ")"); + window.alert(JSON.stringify(xhr)); + //console.log(JSON.stringify(xhr)); + $('#button_runagain_arch').attr('disabled',false); + } + }) + +}) + //edit modal $("#editModalArchive").on('submit','#editFormArchive', function(event){ event.preventDefault(); @@ -325,6 +459,13 @@ var archiveRecords = { targets: [18], render: function ( data, type, row ) { + try { + data = JSON.parse(data) + } + catch (error) { + + } + var res = JSON.stringify(data) const unquoted = res.replace(/"([^"]+)":/g, '$1:') return '
'+unquoted+'
'