diff --git a/testy/changeDict.py b/testy/changeDict.py new file mode 100644 index 0000000..0b3db48 --- /dev/null +++ b/testy/changeDict.py @@ -0,0 +1,50 @@ +from v2realbot.utils.utils import AttributeDict + +stratvars_parsed_old = AttributeDict(maxpozic = 250, + chunk = 10, + MA = 3, + Trend = 3, + profit = 0.02, + lastbuyindex=-6, + pendingbuys={}, + limitka = None, + jevylozeno=0, + vykladka=5, + curve = [0.01, 0.01, 0.01, 0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01], + blockbuy = 0, + ticks2reset = 0.04) + +stratvars_parsed_new = AttributeDict(maxpozic = 250, + chunk = 10, + MA = 3, + Trend = 3, + profit = 0.02, + lastbuyindex=-6, + pendingbuys={}, + limitka = None, + jevylozeno=0, + vykladka=5, + curve = [0.01, 0.01, 0.01, 0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01], + blockbuy = 0, + ticks2reset = 0.04) + + +STRATVARS_UNCHANGEABLES = ['pendingbuys', 'blockbuy', 'jevylozeno', 'limitka'] + +changed_keys = [] +#get changed values +for key,value in stratvars_parsed_new.items(): + if value != stratvars_parsed_old[key]: + changed_keys.append(key) + +print("changed before check", changed_keys) +#remove keys that cannot be changed +for k in changed_keys: + if k in STRATVARS_UNCHANGEABLES: + print(k, "cant be changed removing") + changed_keys.remove(k) + +print("clean changed keys", changed_keys) + +for k in changed_keys: + print("injecting",k, "value", stratvars_parsed_new[k]) diff --git a/testy/gethistorytrades.py b/testy/gethistorytrades.py index bd0320c..8cfe8ec 100644 --- a/testy/gethistorytrades.py +++ b/testy/gethistorytrades.py @@ -4,31 +4,29 @@ print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from alpaca.data.historical import CryptoHistoricalDataClient, StockHistoricalDataClient from alpaca.data.requests import CryptoLatestTradeRequest, StockLatestTradeRequest, StockLatestBarRequest, StockTradesRequest from alpaca.data.enums import DataFeed -from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE +from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY +from v2realbot.utils.utils import zoneNY from datetime import datetime, timezone, time, timedelta, date import pytz from rich import print -#práce s datumy - -zone_NY = pytz.timezone('America/New_York') - parametry = {} symbol = ["BAC"] -client = StockHistoricalDataClient(API_KEY, SECRET_KEY, raw_data=True) -datetime_object_from = datetime(2023, 3, 16, 9, 30, 0, tzinfo=zone_NY) -datetime_object_to = datetime(2023, 3, 16, 16, 00, 0, tzinfo=zone_NY) +client = StockHistoricalDataClient(ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, raw_data=True) +datetime_object_from = datetime(2023, 4, 12, 15, 45, 8, tzinfo=zoneNY) +datetime_object_to = datetime(2023, 4, 12, 15, 45, 10, tzinfo=zoneNY) trades_request = StockTradesRequest(symbol_or_symbols=symbol, feed = DataFeed.SIP, start=datetime_object_from, end=datetime_object_to) all_trades = client.get_stock_trades(trades_request) -#print(all_trades) +print(all_trades) -print(len(all_trades['BAC'])) +# print(len(all_trades['BAC'])) +# print(all_trades['BAC']) # for i in all_trades: # print(all_trades[i]) -if __name__ == "__main__": - # bar will be invoked if this module is being run directly, but not via import! - print("hello") \ No newline at end of file +# if __name__ == "__main__": +# # bar will be invoked if this module is being run directly, but not via import! +# print("hello") \ No newline at end of file diff --git a/v2realbot/ENTRY_backtest_strategyVykladaci.py b/v2realbot/ENTRY_backtest_strategyVykladaci.py index 98c3edb..5291824 100644 --- a/v2realbot/ENTRY_backtest_strategyVykladaci.py +++ b/v2realbot/ENTRY_backtest_strategyVykladaci.py @@ -220,11 +220,11 @@ def main(): name = os.path.basename(__file__) se = Event() pe = Event() - s = StrategyOrderLimitVykladaci(name = name, symbol = "BAC", account=Account.ACCOUNT2, next=next, init=init, stratvars=stratvars, open_rush=40, close_rush=0, pe=pe, se=se) - s.set_mode(mode = Mode.PAPER, + s = StrategyOrderLimitVykladaci(name = name, symbol = "BAC", account=Account.ACCOUNT2, next=next, init=init, stratvars=stratvars, open_rush=10, close_rush=0, pe=pe, se=se) + s.set_mode(mode = Mode.BT, debug = False, - start = datetime(2023, 3, 30, 9, 30, 0, 0, tzinfo=zoneNY), - end = datetime(2023, 3, 31, 16, 0, 0, 0, tzinfo=zoneNY), + start = datetime(2023, 4, 10, 9, 30, 0, 0, tzinfo=zoneNY), + end = datetime(2023, 4, 10, 9, 35, 0, 0, tzinfo=zoneNY), cash=100000) #na sekundovem baru nezaokrouhlovat MAcko diff --git a/v2realbot/__pycache__/config.cpython-310.pyc b/v2realbot/__pycache__/config.cpython-310.pyc index 9de6df8..62b8a15 100644 Binary files a/v2realbot/__pycache__/config.cpython-310.pyc and b/v2realbot/__pycache__/config.cpython-310.pyc differ diff --git a/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc b/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc index c0bdf1a..965fe2d 100644 Binary files a/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc and b/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc differ diff --git a/v2realbot/backtesting/backtester.py b/v2realbot/backtesting/backtester.py index 735e8fd..19b7770 100644 --- a/v2realbot/backtesting/backtester.py +++ b/v2realbot/backtesting/backtester.py @@ -43,7 +43,7 @@ from v2realbot.common.model import TradeUpdate, Order #from rich import print import threading import asyncio -from v2realbot.config import BT_DELAYS +from v2realbot.config import BT_DELAYS, DATA_DIR from v2realbot.utils.utils import AttributeDict, ltp, zoneNY, trunc, count_decimals,print from v2realbot.utils.tlog import tlog from datetime import datetime, timedelta @@ -59,7 +59,6 @@ from v2realbot.utils.dash_save_html import make_static import dash_bootstrap_components as dbc from dash.dependencies import Input, Output from dash import dcc, html, dash_table, Dash -from config import DATA_DIR """" LATENCY DELAYS .000 trigger - last_trade_time (.4246266) @@ -563,8 +562,18 @@ class Backtester: hist_df = hist_df.set_index('time', drop=False) #indicators - ind_df = pd.DataFrame(state.indicators) - ind_df = ind_df.set_index('time', drop=False) + #TODO vyresit if no indicators or no trades - pada na ValueError protoze pole obsahuje time, ale nikoliv indikatory + #zatim jen takto workaround + #print(state.indicators) + try: + ind_df = pd.DataFrame(state.indicators) + ind_df = ind_df.set_index('time', drop=False) + except ValueError as e: + print("Value error", str(e)) + state.indicators = {'time': [] } + ind_df = pd.DataFrame(state.indicators) + ind_df = ind_df.set_index('time', drop=False) + #print("Indicators", ind_df) #print(state.indicators) @@ -801,7 +810,7 @@ class Backtester: if n_clicks == 0: return 'not saved' else: - bt_dir = DATADIR + "/backtestresults/" + self.symbol + self.bp_from.strftime("%d-%m-%y-%H-%M-%S") + ' ' + self.bp_to.strftime("%d-%m-%y-%H-%M-%S") + ' ' + str(datetime.now().microsecond) + bt_dir = DATA_DIR + "/backtestresults/" + self.symbol + self.bp_from.strftime("%d-%m-%y-%H-%M-%S") + ' ' + self.bp_to.strftime("%d-%m-%y-%H-%M-%S") + ' ' + str(datetime.now().microsecond) make_static(f'http://127.0.0.1:{port}/', bt_dir) return 'saved' diff --git a/v2realbot/config.py b/v2realbot/config.py index fcc3d50..05a0592 100644 --- a/v2realbot/config.py +++ b/v2realbot/config.py @@ -2,6 +2,7 @@ from alpaca.data.enums import DataFeed from v2realbot.enums.enums import Mode, Account from appdirs import user_data_dir +STRATVARS_UNCHANGEABLES = ['pendingbuys', 'blockbuy', 'jevylozeno', 'limitka'] DATA_DIR = user_data_dir("v2realbot") #BT DELAYS diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index ce4dff2..646b5b0 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -6,6 +6,7 @@ from v2realbot.common.model import StrategyInstance, Runner, RunRequest from v2realbot.utils.utils import AttributeDict, zoneNY, dict_replace_value, Store, parse_toml_string from datetime import datetime from threading import Thread, current_thread, Event, enumerate +from v2realbot.config import STRATVARS_UNCHANGEABLES import importlib from queue import Queue db = Store() @@ -89,42 +90,68 @@ def delete_stratin(id: UUID): return (0, i.id) return (-2, "not found") -def inject_stratvars(id: UUID, stratvars_parsed: AttributeDict): +def inject_stratvars(id: UUID, stratvars_parsed_new: AttributeDict, stratvars_parsed_old: AttributeDict): for i in db.runners: if str(i.id) == str(id): - i.run_instance.state.vars = AttributeDict(stratvars_parsed["stratvars"]) - i.run_instance.stratvars = AttributeDict(stratvars_parsed["stratvars"]) - return 0 - return -2 + #inject only those changed, some of them cannot be changed (for example pendingbuys) + + changed_keys = [] + #get changed values + for key,value in stratvars_parsed_new.items(): + if value != stratvars_parsed_old[key]: + changed_keys.append(key) + + #print("changed before check", changed_keys) + #remove keys that cannot be changed + for k in changed_keys: + if k in STRATVARS_UNCHANGEABLES: + #print(k, "cant be changed removing") + changed_keys.remove(k) + return -2, "Stratvar Key "+k+" cannot be changed" + + #print("clean changed keys", changed_keys) + #inject clean keys + for k in changed_keys: + print("INJECTING ",k, "value", stratvars_parsed_new[k]) + i.run_instance.state.vars[k] = stratvars_parsed_new[k] + i.run_instance.stratvars[k] = stratvars_parsed_new[k] + return 0, None + return -2, "No runners found" #allows change of set of parameters that are possible to change while it is running #also injects those parameters to instance def modify_stratin_running(si: StrategyInstance, id: UUID): - #validate toml - res,stp = parse_toml_string(si.stratvars_conf) - if res < 0: - return (-1, "stratvars invalid") - for i in db.stratins: - if str(i.id) == str(id): - if not is_stratin_running(id=str(id)): - return (-1, "not running") - i.id2 = si.id2 - i.name = si.name - i.open_rush = si.open_rush - i.stratvars_conf = si.stratvars_conf - i.note = si.note - i.history = si.history - db.save() - #TODO reload running strat - print(stp) - print("starting injection", stp) - res = inject_stratvars(id=si.id, stratvars_parsed=stp) - if res < 0: - print("ajajaj inject se nepovedl") - return(-3, "inject failed") - return (0, i.id) - return (-2, "not found") - #controller.reload_params(si) + try: + #validate toml + res,stp = parse_toml_string(si.stratvars_conf) + if res < 0: + return (-1, "new stratvars format invalid") + for i in db.stratins: + if str(i.id) == str(id): + if not is_stratin_running(id=str(id)): + return (-1, "not running") + res,stp_old = parse_toml_string(i.stratvars_conf) + if res < 0: + return (-1, "current stratin stratvars invalid") + #TODO reload running strat + #print(stp) + #print("starting injection", stp) + res, msg = inject_stratvars(id=si.id, stratvars_parsed_new=stp["stratvars"], stratvars_parsed_old=stp_old["stratvars"]) + if res < 0: + print("ajajaj inject se nepovedl", msg) + return(-3, "inject failed: " + msg) + i.id2 = si.id2 + i.name = si.name + i.open_rush = si.open_rush + i.stratvars_conf = si.stratvars_conf + i.note = si.note + i.history = si.history + db.save() + return (0, i.id) + return (-2, "not found") + except Exception as e: + return (-2, "Error Exception" + str(e)) + ##enable realtime chart - inject given queue for strategy instance ##webservice listens to this queue @@ -208,6 +235,7 @@ def capsule(target: object, db: object): reason = "SHUTDOWN OK" except Exception as e: reason = "SHUTDOWN Exception:" + str(e) + print(reason) finally: # remove runners after thread is stopped and save results to stratin history for i in db.runners: diff --git a/v2realbot/loader/__pycache__/aggregator.cpython-310.pyc b/v2realbot/loader/__pycache__/aggregator.cpython-310.pyc index 5ca646e..8189667 100644 Binary files a/v2realbot/loader/__pycache__/aggregator.cpython-310.pyc and b/v2realbot/loader/__pycache__/aggregator.cpython-310.pyc differ diff --git a/v2realbot/loader/aggregator.py b/v2realbot/loader/aggregator.py index 3b7fec6..41271c0 100644 --- a/v2realbot/loader/aggregator.py +++ b/v2realbot/loader/aggregator.py @@ -77,10 +77,11 @@ class TradeAggregator: #print(data) ##implementing fitlers - zatim natvrdo a jen tyto: size: 1, cond in [O,C,4] opening,closed a derivately priced, ## 22.3. - dal jsem pryc i contingency trades [' ', '7', 'V'] - nasel jsem obchod o 30c mimo + ## dán pryč P - prior reference time + 25centu mimo, {'t': '2023-04-12T19:45:08.63257344Z', 'x': 'D', 'p': 28.68, 's': 1000, 'c': [' ', 'P'], 'i': 71693108525109, 'z': 'A'}, ## Q - jsou v pohode, oteviraci trady, ale O jsou jejich duplikaty try: for i in data['c']: - if i in ('C','O','4','B','7','V'): return 0 + if i in ('C','O','4','B','7','V','P'): return 0 except KeyError: pass diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index fa1ac66..9f1a47c 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -228,7 +228,7 @@
- +