na FE: runagain button + compare profits func

This commit is contained in:
David Brazda
2023-09-17 11:22:40 +02:00
parent 75d4a82c70
commit dc4d0b8601
6 changed files with 177 additions and 16 deletions

View File

@ -426,7 +426,25 @@ def next(data, state: StrategyState):
elif mode == "pct": elif mode == "pct":
val = pct_diff(num1=float(source1_series[-1]),num2=float(source2_series[-1])) val = pct_diff(num1=float(source1_series[-1]),num2=float(source2_series[-1]))
return 0, val 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 #rate of change - last value of source indicator vs lookback value of lookback_priceline indicator
def slope(params): def slope(params):
funcName = "slope" funcName = "slope"

View File

@ -207,7 +207,7 @@ class RunArchive(BaseModel):
trade_count: int = 0 trade_count: int = 0
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, str] = None
stratvars_toml: Optional[str] = None stratvars_toml: Optional[str] = None
#trida pro ukladani historie stoplossy do ext_data #trida pro ukladani historie stoplossy do ext_data

View File

@ -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[max_positions['side'] == OrderSide.SELL]
max_positions = max_positions.drop(columns=['side'], axis=1) max_positions = max_positions.drop(columns=['side'], axis=1)
res = dict(profit={})
#filt = max_positions['side'] == 'OrderSide.BUY' #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 #naplneni batch sum profitu
if inter_batch_params is not None: 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 #metrikz z prescribedTrades, pokud existuji
try: try:
@ -603,16 +604,16 @@ def populate_metrics_output_directory(strat: StrategyInstance, inter_batch_param
short_losses += trade.profit short_losses += trade.profit
if trade.profit > 0: if trade.profit > 0:
short_wins += trade.profit short_wins += trade.profit
res["long_cnt"] = long_cnt res["profit"]["long_cnt"] = long_cnt
res["short_cnt"] = short_cnt res["profit"]["short_cnt"] = short_cnt
res["long_profit"] = round(long_profit,2) res["profit"]["long_profit"] = round(long_profit,2)
res["short_profit"] = round(short_profit,2) res["profit"]["short_profit"] = round(short_profit,2)
res["long_losses"] = round(long_losses,2) res["profit"]["long_losses"] = round(long_losses,2)
res["short_losses"] = round(short_losses,2) res["profit"]["short_losses"] = round(short_losses,2)
res["long_wins"] = round(long_wins,2) res["profit"]["long_wins"] = round(long_wins,2)
res["short_wins"] = round(short_wins,2) res["profit"]["short_wins"] = round(short_wins,2)
res["max_profit"] = round(max_profit,2) res["profit"]["max_profit"] = round(max_profit,2)
res["max_profit_time"] = str(max_profit_time) res["profit"]["max_profit_time"] = str(max_profit_time)
#vlozeni celeho listu #vlozeni celeho listu
res["prescr_trades"]=json.loads(json.dumps(strat.state.vars.prescribedTrades, default=json_serial)) 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), 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=json.dumps(results_metrics, default=json_serial),
stratvars_toml=runner.run_stratvars_toml stratvars_toml=runner.run_stratvars_toml
) )

View File

@ -181,6 +181,7 @@
<button id="button_show_arch" class="btn btn-outline-success btn-sm">Show</button> <button id="button_show_arch" class="btn btn-outline-success btn-sm">Show</button>
<button id="button_refresh" class="refresh btn btn-outline-success btn-sm">Refresh</button> <button id="button_refresh" class="refresh btn btn-outline-success btn-sm">Refresh</button>
<button id="button_compare_arch" class="refresh btn btn-outline-success btn-sm">Compare</button> <button id="button_compare_arch" class="refresh btn btn-outline-success btn-sm">Compare</button>
<button id="button_runagain_arch" class="refresh btn btn-outline-success btn-sm">Run Again</button>
<!-- <button id="button_stopall" class="btn btn-outline-success btn-sm">Stop All</button> <!-- <button id="button_stopall" class="btn btn-outline-success btn-sm">Stop All</button>
<button id="button_refresh" class="btn btn-outline-success btn-sm">Refresh</button> --> <button id="button_refresh" class="btn btn-outline-success btn-sm">Refresh</button> -->
</div> </div>

View File

@ -8,6 +8,7 @@ $(document).ready(function () {
}); });
//disable buttons (enable on row selection) //disable buttons (enable on row selection)
$('#button_runagain_arch').attr('disabled','disabled');
$('#button_show_arch').attr('disabled','disabled'); $('#button_show_arch').attr('disabled','disabled');
$('#button_delete_arch').attr('disabled','disabled'); $('#button_delete_arch').attr('disabled','disabled');
$('#button_edit_arch').attr('disabled','disabled'); $('#button_edit_arch').attr('disabled','disabled');
@ -18,6 +19,7 @@ $(document).ready(function () {
if ($(this).hasClass('selected')) { if ($(this).hasClass('selected')) {
//$(this).removeClass('selected'); //$(this).removeClass('selected');
$('#button_show_arch').attr('disabled','disabled'); $('#button_show_arch').attr('disabled','disabled');
$('#button_runagain_arch').attr('disabled','disabled');
$('#button_delete_arch').attr('disabled','disabled'); $('#button_delete_arch').attr('disabled','disabled');
$('#button_edit_arch').attr('disabled','disabled'); $('#button_edit_arch').attr('disabled','disabled');
$('#button_compare_arch').attr('disabled','disabled'); $('#button_compare_arch').attr('disabled','disabled');
@ -25,6 +27,7 @@ $(document).ready(function () {
//archiveRecords.$('tr.selected').removeClass('selected'); //archiveRecords.$('tr.selected').removeClass('selected');
$(this).addClass('selected'); $(this).addClass('selected');
$('#button_show_arch').attr('disabled',false); $('#button_show_arch').attr('disabled',false);
$('#button_runagain_arch').attr('disabled',false);
$('#button_delete_arch').attr('disabled',false); $('#button_delete_arch').attr('disabled',false);
$('#button_edit_arch').attr('disabled',false); $('#button_edit_arch').attr('disabled',false);
$('#button_compare_arch').attr('disabled',false); $('#button_compare_arch').attr('disabled',false);
@ -51,6 +54,18 @@ $(document).ready(function () {
// record1.close_rush = rows[0].close_rush; // record1.close_rush = rows[0].close_rush;
//console.log(record1.stratvars_conf) //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.stratvars_conf = TOML.parse(record1.stratvars_conf);
record1.add_data_conf = TOML.parse(record1.add_data_conf); record1.add_data_conf = TOML.parse(record1.add_data_conf);
// record1.note = rows[0].note; // record1.note = rows[0].note;
@ -69,6 +84,15 @@ $(document).ready(function () {
// record2.open_rush = rows[1].open_rush; // record2.open_rush = rows[1].open_rush;
// record2.close_rush = rows[1].close_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.stratvars_conf = TOML.parse(record2.stratvars_conf);
record2.add_data_conf = TOML.parse(record2.add_data_conf); record2.add_data_conf = TOML.parse(record2.add_data_conf);
// record2.note = rows[1].note; // record2.note = rows[1].note;
@ -117,7 +141,15 @@ $(document).ready(function () {
window.$('#editModalArchive').modal('show'); window.$('#editModalArchive').modal('show');
$('#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));
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)); //$('#metrics').val(TOML.parse(row.open_orders));
if (row.stratvars_toml) { if (row.stratvars_toml) {
$('#editstratvars').val(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 //edit modal
$("#editModalArchive").on('submit','#editFormArchive', function(event){ $("#editModalArchive").on('submit','#editFormArchive', function(event){
event.preventDefault(); event.preventDefault();
@ -325,6 +459,13 @@ var archiveRecords =
{ {
targets: [18], targets: [18],
render: function ( data, type, row ) { render: function ( data, type, row ) {
try {
data = JSON.parse(data)
}
catch (error) {
}
var res = JSON.stringify(data) var res = JSON.stringify(data)
const unquoted = res.replace(/"([^"]+)":/g, '$1:') const unquoted = res.replace(/"([^"]+)":/g, '$1:')
return '<div class="tdmetrics" title="'+unquoted+'">'+unquoted+'</div>' return '<div class="tdmetrics" title="'+unquoted+'">'+unquoted+'</div>'