diff --git a/testy/pickle.py b/testy/pickle.py new file mode 100644 index 0000000..aaa0d38 --- /dev/null +++ b/testy/pickle.py @@ -0,0 +1,39 @@ +import pickle +import os +from v2realbot.config import STRATVARS_UNCHANGEABLES, ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, DATA_DIR,BT_FILL_CONS_TRADES_REQUIRED,BT_FILL_LOG_SURROUNDING_TRADES,BT_FILL_CONDITION_BUY_LIMIT,BT_FILL_CONDITION_SELL_LIMIT, GROUP_TRADES_WITH_TIMESTAMP_LESS_THAN, MEDIA_DIRECTORY, RUNNER_DETAIL_DIRECTORY + +# #class to persist +# class Store: +# stratins : List[StrategyInstance] = [] +# runners: List[Runner] = [] +# def __init__(self) -> None: +# self.db_file = DATA_DIR + "/strategyinstances.cache" +# if os.path.exists(self.db_file): +# with open (self.db_file, 'rb') as fp: +# self.stratins = pickle.load(fp) + +# def save(self): +# with open(self.db_file, 'wb') as fp: +# pickle.dump(self.stratins, fp) + + +#db = Store() + +def try_reading_after_skipping_bytes(file_path, skip_bytes, chunk_size=1024): + with open(file_path, 'rb') as file: + file.seek(skip_bytes) # Skip initial bytes + while True: + try: + data = pickle.load(file) + print("Recovered data:", data) + break # Exit loop if successful + except EOFError: + print("Reached end of file without recovering data.") + break + except pickle.UnpicklingError: + # Move ahead in file by chunk_size bytes and try again + file.seek(file.tell() + chunk_size, os.SEEK_SET) + + +file_path = DATA_DIR + "/strategyinstances.cache" +try_reading_after_skipping_bytes(file_path,1) \ No newline at end of file diff --git a/v2realbot/ENTRY_ClassicSL_v01.py b/v2realbot/ENTRY_ClassicSL_v01.py index 17fbd42..ad64cf6 100644 --- a/v2realbot/ENTRY_ClassicSL_v01.py +++ b/v2realbot/ENTRY_ClassicSL_v01.py @@ -20,6 +20,9 @@ from alpaca.trading.requests import GetCalendarRequest from alpaca.trading.client import TradingClient from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, DATA_DIR, OFFLINE_MODE from alpaca.trading.models import Calendar +from v2realbot.indicators.oscillators import rsi +from v2realbot.indicators.moving_averages import sma +import numpy as np print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) """" @@ -161,7 +164,7 @@ def init(state: StrategyState): #time_to = time_to.date() today = time_to.date() - several_days_ago = today - timedelta(days=40) + several_days_ago = today - timedelta(days=60) #printanyway(f"{today=}",f"{several_days_ago=}") clientTrading = TradingClient(ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, raw_data=False) #get all market days from here to 40days ago @@ -190,6 +193,30 @@ def init(state: StrategyState): #printanyway(history_datetime_from, history_datetime_to) #az do predchziho market dne dne state.dailyBars = get_historical_bars(state.symbol, history_datetime_from, history_datetime_to, TimeFrame.Day) + + #NOTE zatim pridano takto do baru dalsi indikatory + #BUDE PREDELANO - v rámci custom rozliseni a static indikátoru + + #RSI vraci pouze pro vsechny + prepend with zeros nepocita prvnich N (dle rsi length) + rsi_calculated = rsi(state.dailyBars["vwap"], 14).tolist() + num_zeros_to_prepend = len(state.dailyBars["vwap"]) - len(rsi_calculated) + state.dailyBars["rsi"] = [0]*num_zeros_to_prepend + rsi_calculated + + #VOLUME + volume_sma = sma(state.dailyBars["volume"], 10) #vraci celkovy pocet - 10 + items_to_prepend = len(state.dailyBars["volume"]) - len(volume_sma) + + volume_sma = np.hstack((np.full(items_to_prepend, np.nan), volume_sma)) + + #normalized divergence currvol-smavolume/currvol+smavolume + volume_data = np.array(state.dailyBars["volume"]) + normalized_divergence = (volume_data - volume_sma) / (volume_data + volume_sma) + # Replace NaN values with 0 or some other placeholder if needed + normalized_divergence = np.nan_to_num(normalized_divergence) + volume_sma = np.nan_to_num(volume_sma) + state.dailyBars["volume_sma_divergence"] = normalized_divergence.tolist() + state.dailyBars["volume_sma"] = volume_sma.tolist() + #printanyway("daily bars FILLED", state.dailyBars) #zatim ukladame do extData - pro instant indicatory a gui state.extData["dailyBars"] = state.dailyBars diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index cef6965..bf5aa23 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -1551,7 +1551,7 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool = local_dict_inds = {key: state.indicators[key] for key in state.indicators.keys() if key != "time"} local_dict_bars = {key: state.bars[key] for key in state.bars.keys() if key != "time"} state.ind_mapping = {**local_dict_inds, **local_dict_bars, **local_dict_cbar_inds} - print("IND MAPPING DONE:", state.ind_mapping) + #print("IND MAPPING DONE:", state.ind_mapping) ##intialize dynamic indicators initialize_dynamic_indicators(state) diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index 581cde7..9ea038a 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -696,8 +696,8 @@
- - + +
diff --git a/v2realbot/static/js/libs/dataTables.bootstrap5.min.css b/v2realbot/static/js/libs/dataTables.bootstrap5.min.css index 3df6787..b4c4cdd 100644 --- a/v2realbot/static/js/libs/dataTables.bootstrap5.min.css +++ b/v2realbot/static/js/libs/dataTables.bootstrap5.min.css @@ -2,4 +2,4 @@ * * ©2020 SpryMedia Ltd, all rights reserved. * License: MIT datatables.net/license/mit - */table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important;border-spacing:0}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.table-striped>tbody>tr:nth-of-type(2n+1)>*{box-shadow:none}table.dataTable>tbody>tr{background-color:transparent}table.dataTable>tbody>tr.selected>*{box-shadow:inset 0 0 0 9999px rgb(13, 110, 253);box-shadow:inset 0 0 0 9999px rgb(var(--dt-row-selected));color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable>tbody>tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable.table-striped>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.05)}table.dataTable.table-striped>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.95);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.95)}table.dataTable.table-hover>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.075)}table.dataTable.table-hover>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.975);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.975)}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:auto;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:.85em}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap;justify-content:flex-end}div.dataTables_wrapper div.dt-row{position:relative}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody>table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody>table>thead .sorting:before,div.dataTables_scrollBody>table>thead .sorting_asc:before,div.dataTables_scrollBody>table>thead .sorting_desc:before,div.dataTables_scrollBody>table>thead .sorting:after,div.dataTables_scrollBody>table>thead .sorting_asc:after,div.dataTables_scrollBody>table>thead .sorting_desc:after{display:none}div.dataTables_scrollBody>table>tbody tr:first-child th,div.dataTables_scrollBody>table>tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot>.dataTables_scrollFootInner{box-sizing:content-box}div.dataTables_scrollFoot>.dataTables_scrollFootInner>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}div.dataTables_wrapper div.dataTables_paginate ul.pagination{justify-content:center !important}}table.dataTable.table-sm>thead>tr>th:not(.sorting_disabled){padding-right:20px}table.table-bordered.dataTable{border-right-width:0}table.table-bordered.dataTable thead tr:first-child th,table.table-bordered.dataTable thead tr:first-child td{border-top-width:1px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:first-child,table.table-bordered.dataTable th:first-child,table.table-bordered.dataTable td:first-child,table.table-bordered.dataTable td:first-child{border-left-width:1px}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:1px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-bottom-width:1px}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^=col-]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^=col-]:last-child{padding-right:0} + */table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important;border-spacing:0}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}/*table.dataTable.table-striped>tbody>tr:nth-of-type(2n+1)>*{box-shadow:none}*/table.dataTable>tbody>tr{background-color:transparent}table.dataTable>tbody>tr.selected>*{box-shadow:inset 0 0 0 9999px rgb(13, 110, 253);box-shadow:inset 0 0 0 9999px rgb(var(--dt-row-selected));color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable>tbody>tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable.table-striped>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.05)}table.dataTable.table-striped>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.95);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.95)}table.dataTable.table-hover>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.075)}table.dataTable.table-hover>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.975);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.975)}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:auto;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:.85em}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap;justify-content:flex-end}div.dataTables_wrapper div.dt-row{position:relative}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody>table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody>table>thead .sorting:before,div.dataTables_scrollBody>table>thead .sorting_asc:before,div.dataTables_scrollBody>table>thead .sorting_desc:before,div.dataTables_scrollBody>table>thead .sorting:after,div.dataTables_scrollBody>table>thead .sorting_asc:after,div.dataTables_scrollBody>table>thead .sorting_desc:after{display:none}div.dataTables_scrollBody>table>tbody tr:first-child th,div.dataTables_scrollBody>table>tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot>.dataTables_scrollFootInner{box-sizing:content-box}div.dataTables_scrollFoot>.dataTables_scrollFootInner>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}div.dataTables_wrapper div.dataTables_paginate ul.pagination{justify-content:center !important}}table.dataTable.table-sm>thead>tr>th:not(.sorting_disabled){padding-right:20px}table.table-bordered.dataTable{border-right-width:0}table.table-bordered.dataTable thead tr:first-child th,table.table-bordered.dataTable thead tr:first-child td{border-top-width:1px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:first-child,table.table-bordered.dataTable th:first-child,table.table-bordered.dataTable td:first-child,table.table-bordered.dataTable td:first-child{border-left-width:1px}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:1px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-bottom-width:1px}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^=col-]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^=col-]:last-child{padding-right:0} diff --git a/v2realbot/static/js/mytables.js b/v2realbot/static/js/mytables.js index f106f8e..040e9cb 100644 --- a/v2realbot/static/js/mytables.js +++ b/v2realbot/static/js/mytables.js @@ -636,7 +636,7 @@ $(document).ready(function () { $('#bt_to').val(localStorage.getItem("bt_to")); //console.log(localStorage.getItem("bt_to")) $('#test_batch_id').val(localStorage.getItem("test_batch_id")); - $('#mode').val(localStorage.getItem("mode")); + $('#runmode').val(localStorage.getItem("runmode")); $('#account').val(localStorage.getItem("account")); $('#debug').val(localStorage.getItem("debug")); $('#ilog_save').val(localStorage.getItem("ilog_save")); @@ -965,7 +965,9 @@ $("#runModal").on('submit','#runForm', function(event){ localStorage.setItem("bt_from", $('#bt_from').val()); localStorage.setItem("bt_to", $('#bt_to').val()); localStorage.setItem("test_batch_id", $('#test_batch_id').val()); - localStorage.setItem("mode", $('#mode').val()); + localStorage.setItem("runmode", $('#runmode').val()); + console.log("mode set to", $('#runmode').val()) + console.log("mode loaded value", localStorage.getItem("runmode")) localStorage.setItem("account", $('#account').val()); localStorage.setItem("debug", $('#debug').val()); localStorage.setItem("ilog_save", $('#ilog_save').val()); diff --git a/v2realbot/static/main.css b/v2realbot/static/main.css index 54e2f20..7f659fb 100644 --- a/v2realbot/static/main.css +++ b/v2realbot/static/main.css @@ -194,15 +194,16 @@ strong { [data-bs-theme=dark] { --bs-font-sans-serif: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --bs-body-line-height: 1.3; - --bs-body-font-size: 1.0rem; + --bs-body-font-size: 1.125rem; --bs-body-font-weight: 300; color-scheme: dark; - --bs-body-color: #787b86; + --bs-body-color: #a1a1a1; + /* --bs-body-color: #787b86; */ --bs-body-color-rgb: 173,181,189; /* --bs-body-bg: #2a2e39; */ --bs-body-bg: #121722; --bs-body-bg-rgb: 33,37,41; - --bs-emphasis-color: #adb5bd; + --bs-emphasis-color: #c8c8c8; --bs-emphasis-color-rgb: 255,255,255; --bs-secondary-color: rgba(173, 181, 189, 0.75); --bs-secondary-color-rgb: 173,181,189; @@ -337,7 +338,7 @@ table.dataTable thead>tr>th.sorting_asc:before, table.dataTable thead>tr>th.sort /* #128faf; */ .btn-outline-success { - --bs-btn-color: #75a9ac; + --bs-btn-color: #94b1b3; --bs-btn-border-color: #8b8b8b; --bs-btn-hover-color: #fff; --bs-btn-hover-bg: #3996a4; diff --git a/v2realbot/strategyblocks/indicators/custom/classes/DayTime.py b/v2realbot/strategyblocks/indicators/custom/classes/DayTime.py new file mode 100644 index 0000000..ba65ee1 --- /dev/null +++ b/v2realbot/strategyblocks/indicators/custom/classes/DayTime.py @@ -0,0 +1,29 @@ +from v2realbot.strategyblocks.indicators.custom.classes.indicatorbase import IndicatorBase +from datetime import datetime, time +from v2realbot.utils.utils import zoneNY + +class DayTime(IndicatorBase): + def __init__(self, state): + super().__init__(state) + #TODO toto v initu dynamicky + # Convert market open/close times to seconds since epoch + self.market_open_time = self._time_to_seconds_since_epoch(time(9, 30), state) + self.market_close_time = self._time_to_seconds_since_epoch(time(16, 0), state) + # Total market duration in seconds + self.total_market_duration = self.market_close_time - self.market_open_time + + def _time_to_seconds_since_epoch(self, market_time, state): + # Convert a time object to seconds since epoch for a typical day (e.g., today) + today = datetime.fromtimestamp(state.time).astimezone(zoneNY).date() + market_datetime = zoneNY.localize(datetime.combine(today, market_time)) + return market_datetime.timestamp() + + def next(self, time): + current_timestamp = time[-1] + # Check if the current time is within market hours + if self.market_open_time <= current_timestamp <= self.market_close_time: + time_since_open = current_timestamp - self.market_open_time + normalized_time = time_since_open / self.total_market_duration + return normalized_time + else: + return 0 \ No newline at end of file diff --git a/v2realbot/strategyblocks/indicators/custom/classes/WeekDay.py b/v2realbot/strategyblocks/indicators/custom/classes/WeekDay.py new file mode 100644 index 0000000..dd975d4 --- /dev/null +++ b/v2realbot/strategyblocks/indicators/custom/classes/WeekDay.py @@ -0,0 +1,12 @@ +from v2realbot.strategyblocks.indicators.custom.classes.indicatorbase import IndicatorBase +from datetime import datetime, time +from v2realbot.utils.utils import zoneNY + +#do budoucna predelat na staticky indikator +class WeekDay(IndicatorBase): + def __init__(self, state): + super().__init__(state) + self.weekday = datetime.fromtimestamp(state.time).astimezone(zoneNY).weekday() + + def next(self): + return self.weekday \ No newline at end of file diff --git a/v2realbot/strategyblocks/indicators/custom/target.py b/v2realbot/strategyblocks/indicators/custom/target.py index 40812d4..520b959 100644 --- a/v2realbot/strategyblocks/indicators/custom/target.py +++ b/v2realbot/strategyblocks/indicators/custom/target.py @@ -61,7 +61,11 @@ def target(state, params, name): if split_index == -1: return -2, "for second based window length, source is required in format bars|close" dict_name = source[:split_index] - time_series = getattr(state, dict_name)["time"] + if dict_name == "bars": + #u baru je time v datetime, proto bereme udpated + time_series = getattr(state, dict_name)["updated"] + else: + time_series = getattr(state, dict_name)["time"] state.cache[name]["time_series"] = time_series else: time_series = state.cache[name]["time_series"]