diff --git a/v2realbot/common/model.py b/v2realbot/common/model.py index fc23955..2650990 100644 --- a/v2realbot/common/model.py +++ b/v2realbot/common/model.py @@ -88,6 +88,9 @@ class RunRequest(BaseModel): ilog_save: bool = False bt_from: datetime = None bt_to: datetime = None + #weekdays filter + #pokud je uvedeny filtrujeme tyto dny + weekdays_filter: Optional[list] = None #id testovaciho intervalu TODO prejmenovat test_batch_id: Optional[str] = None #GENERATED ID v ramci runu, vaze vsechny runnery v batchovem behu diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index 023184e..57c14ca 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -8,7 +8,7 @@ from alpaca.data.timeframe import TimeFrame from v2realbot.strategy.base import StrategyState from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide from v2realbot.common.model import RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem, InstantIndicator -from v2realbot.utils.utils import AttributeDict, zoneNY, zonePRG, safe_get, dict_replace_value, Store, parse_toml_string, json_serial, is_open_hours, send_to_telegram +from v2realbot.utils.utils import AttributeDict, zoneNY, zonePRG, safe_get, dict_replace_value, Store, parse_toml_string, json_serial, is_open_hours, send_to_telegram, concatenate_weekdays from v2realbot.utils.ilog import delete_logs from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType from datetime import datetime @@ -410,7 +410,8 @@ def run_batch_stratin(id: UUID, runReq: RunRequest): end_time = dateto cal_list.append(RunDay(start = start_time, end = end_time, note = note, id = id)) - print(f"Getting interval dates from - to - RESULT ({len(cal_list)}): {cal_list}") + print(f"Getting interval dates from - to - RESULT ({len(cal_list)}):") + print(cal_list) return cal_list #getting days to run into RunDays format @@ -474,19 +475,34 @@ def batch_run_manager(id: UUID, runReq: RunRequest, rundays: list[RunDay]): rundays.sort(key=lambda x: x.start) #print("RUNDAYS after sort:", rundays) + #APPLY WEEKDAYS filter - necháváme pouze ty, ktere jsou uvedene + if runReq.weekdays_filter is not None: + rundays = [run_day for run_day in rundays if run_day.start.weekday() in runReq.weekdays_filter] + + if len(rundays) == 0: + print("No eligible DAYS") + return + cnt_max = len(rundays) cnt = 0 #promenna pro sdileni mezi runy jednotlivych batchů (např. daily profit) inter_batch_params = dict(batch_profit=0, batch_rel_profit=0) note_from_run_request = runReq.note first = None + first_frm = None last = None + last_frm = None # Find the minimum start date and maximum end date to add to Note first = min(runday.start for runday in rundays) last = max(runday.end for runday in rundays) first_frm = first.strftime("%d.%m.") - last_frm = last.strftime("%d.%m.") + last_frm = last.strftime("%d.%m.") + + weekdayfilter_string = "" + if runReq.weekdays_filter is not None: + weekdayfilter_string = concatenate_weekdays(runReq.weekdays_filter) + weekdayfilter_string = "DAYS:" + weekdayfilter_string.upper() if weekdayfilter_string != '' else '' for day in rundays: cnt += 1 @@ -494,7 +510,7 @@ def batch_run_manager(id: UUID, runReq: RunRequest, rundays: list[RunDay]): print("Datum do", day.end) runReq.bt_from = day.start runReq.bt_to = day.end - runReq.note = f"{first_frm}-{last_frm} Batch {batch_id} #{cnt}/{cnt_max} {day.name} N:{day.note} {note_from_run_request}" + runReq.note = f"{first_frm}-{last_frm} Batch {batch_id} #{cnt}/{cnt_max} {weekdayfilter_string} {day.name} N:{day.note} {note_from_run_request}" #protoze jsme v ridicim vlaknu, poustime za sebou jednotlive stratiny v synchronnim modu res, id_val = run_stratin(id=id, runReq=runReq, synchronous=True, inter_batch_params=inter_batch_params) diff --git a/v2realbot/main.py b/v2realbot/main.py index c942b3a..d40ccb7 100644 --- a/v2realbot/main.py +++ b/v2realbot/main.py @@ -247,6 +247,8 @@ def _run_stratin(stratin_id: UUID, runReq: RunRequest): if runReq.mode != Mode.LIVE and runReq.test_batch_id is not None or (runReq.bt_from.date() != runReq.bt_to.date()): res, id = cs.run_batch_stratin(id=stratin_id, runReq=runReq) else: + if runReq.weekdays_filter is not None: + raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Weekday only for backtest mode with batch (not single day)") res, id = cs.run_stratin(id=stratin_id, runReq=runReq) if res == 0: return id elif res < 0: diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index 4ff4877..44d34c5 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -703,6 +703,40 @@ + + +
+
+ + +
+
+ + + +
diff --git a/v2realbot/static/js/archivetables.js b/v2realbot/static/js/archivetables.js index dd2f2e2..a53ad9e 100644 --- a/v2realbot/static/js/archivetables.js +++ b/v2realbot/static/js/archivetables.js @@ -558,6 +558,7 @@ $(document).ready(function () { if (row == undefined || row.batch_id == undefined) { return } + $('#deletebatch').attr('disabled', 'disabled'); $.ajax({ url:"/archived_runners/batch/"+row.batch_id, beforeSend: function (xhr) { @@ -569,7 +570,8 @@ $(document).ready(function () { data: JSON.stringify(row.batch_id), success:function(data){ $('#delFormBatch')[0].reset(); - window.$('#delModalBatch').modal('hide'); + window.$('#delModalBatch').modal('hide'); + $('#deletebatch').attr('disabled', false); $('#button_delete_batch').attr('disabled', false); //console.log(data) archiveRecords.ajax.reload(); @@ -578,6 +580,7 @@ $(document).ready(function () { var err = eval("(" + xhr.responseText + ")"); window.alert(JSON.stringify(xhr)); console.log(JSON.stringify(xhr)); + $('#deletebatch').attr('disabled', false); $('#button_delete_batch').attr('disabled', false); archiveRecords.ajax.reload(); } diff --git a/v2realbot/static/js/mytables.js b/v2realbot/static/js/mytables.js index c94142a..1872e13 100644 --- a/v2realbot/static/js/mytables.js +++ b/v2realbot/static/js/mytables.js @@ -625,6 +625,8 @@ $(document).ready(function () { if (row == undefined) { return } + $('#enable_weekdays').prop('checked', false); + $('.weekday-checkboxes').hide(); window.$('#runModal').modal('show'); $('#bt_from').val(localStorage.getItem("bt_from")); //console.log(localStorage.getItem("bt_from")) @@ -654,7 +656,14 @@ $(document).ready(function () { $("#bt_from, #bt_to").prop("disabled", false); } }); - + //listen for changes on weekday enabling button + $('#enable_weekdays').change(function() { + if ($(this).is(':checked')) { + $('.weekday-checkboxes').show(); + } else { + $('.weekday-checkboxes').hide(); + } + }); }); @@ -865,10 +874,33 @@ $("#runModal").on('submit','#runForm', function(event){ event.preventDefault(); $('#run').attr('disabled','disabled'); + // Handle weekdays functionality + var weekdays = []; + if ($('#enable_weekdays').is(':checked')) { + $('#runForm input[name="weekdays"]:checked').each(function() { + var weekday = $(this).val(); + switch(weekday) { + case 'monday': weekdays.push(0); break; + case 'tuesday': weekdays.push(1); break; + case 'wednesday': weekdays.push(2); break; + case 'thursday': weekdays.push(3); break; + case 'friday': weekdays.push(4); break; + // Add cases for Saturday and Sunday if needed + } + }); + } + var formData = $(this).serializeJSON(); //rename runid to id Object.defineProperty(formData, "id", Object.getOwnPropertyDescriptor(formData, "runid")); delete formData["runid"]; + delete formData["enable_weekdays"] + delete formData["weekdays"] + + //pokud je zatrzeno tak aplikujeme filter, jinak nevyplnujeme + if (weekdays.length > 0) { + formData.weekdays_filter = weekdays + } console.log(formData) if ($('#ilog_save').prop('checked')) { formData.ilog_save = true; diff --git a/v2realbot/utils/utils.py b/v2realbot/utils/utils.py index d2cc6f1..3c45a73 100644 --- a/v2realbot/utils/utils.py +++ b/v2realbot/utils/utils.py @@ -27,6 +27,16 @@ from collections import deque import socket import numpy as np +def concatenate_weekdays(weekday_filter): + # Mapping of weekdays where 0 is Monday and 6 is Sunday + weekdays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + + # Convert the integers in weekday_filter to their corresponding weekday strings + weekday_strings = [weekdays[day] for day in weekday_filter] + + # Concatenate the weekday strings + return '-'.join(weekday_strings) + def slice_dict_lists(d, last_item, to_tmstp = False): """Slices every list in the dictionary to the last last_item items.