From d0920daa163930c2dfbd52937350c1dcb33c4d8a Mon Sep 17 00:00:00 2001 From: David Brazda Date: Mon, 26 Feb 2024 19:35:19 +0700 Subject: [PATCH] moved config related services into separated package --- v2realbot/common/db.py | 2 +- v2realbot/config.py | 5 +- v2realbot/controller/configs.py | 108 +++++++++++++++++++++++++++++++ v2realbot/controller/services.py | 98 +++------------------------- v2realbot/main.py | 15 +++-- 5 files changed, 129 insertions(+), 99 deletions(-) create mode 100644 v2realbot/controller/configs.py diff --git a/v2realbot/common/db.py b/v2realbot/common/db.py index 6a44c8a..8c9ed5a 100644 --- a/v2realbot/common/db.py +++ b/v2realbot/common/db.py @@ -1,4 +1,3 @@ -from v2realbot.config import DATA_DIR import sqlite3 import queue import threading @@ -9,6 +8,7 @@ import orjson from v2realbot.utils.utils import json_serial, send_to_telegram, zoneNY import v2realbot.controller.services as cs from uuid import UUID +from v2realbot.config import DATA_DIR sqlite_db_file = DATA_DIR + "/v2trading.db" # Define the connection pool diff --git a/v2realbot/config.py b/v2realbot/config.py index 8c2b701..79ce425 100644 --- a/v2realbot/config.py +++ b/v2realbot/config.py @@ -3,11 +3,14 @@ from v2realbot.enums.enums import Mode, Account, FillCondition from appdirs import user_data_dir from pathlib import Path import os - +from collections import defaultdict # Global flag to track if the ml module has been imported (solution for long import times of tensorflow) #the first occurence of using it will load it globally _ml_module_loaded = False +#TBD - konfiguracni dict issue #148 +#CFG: defaultdict = defaultdict(None) + #directory for generated images and basic reports MEDIA_DIRECTORY = Path(__file__).parent.parent.parent / "media" RUNNER_DETAIL_DIRECTORY = Path(__file__).parent.parent.parent / "runner_detail" diff --git a/v2realbot/controller/configs.py b/v2realbot/controller/configs.py new file mode 100644 index 0000000..ff50d25 --- /dev/null +++ b/v2realbot/controller/configs.py @@ -0,0 +1,108 @@ +import config as cfg +from v2realbot.common.db import pool +from v2realbot.common.model import RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveViewPagination, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem, InstantIndicator, DataTablesRequest +import orjson + +# region CONFIG db services +#TODO vytvorit modul pro dotahovani z pythonu (get_from_config(var_name, def_value) {)- stejne jako v js +#TODO zvazit presunuti do TOML z JSONu +def get_all_config_items(): + conn = pool.get_connection() + try: + cursor = conn.cursor() + cursor.execute('SELECT id, item_name, json_data FROM config_table') + config_items = [{"id": row[0], "item_name": row[1], "json_data": row[2]} for row in cursor.fetchall()] + finally: + pool.release_connection(conn) + return 0, config_items + +# Function to get a config item by ID +def get_config_item_by_id(item_id): + conn = pool.get_connection() + try: + cursor = conn.cursor() + cursor.execute('SELECT item_name, json_data FROM config_table WHERE id = ?', (item_id,)) + row = cursor.fetchone() + finally: + pool.release_connection(conn) + if row is None: + return -2, "not found" + else: + return 0, {"item_name": row[0], "json_data": row[1]} + +# Function to get a config item by ID +def get_config_item_by_name(item_name): + #print(item_name) + conn = pool.get_connection() + try: + cursor = conn.cursor() + query = f"SELECT item_name, json_data FROM config_table WHERE item_name = '{item_name}'" + #print(query) + cursor.execute(query) + row = cursor.fetchone() + #print(row) + finally: + pool.release_connection(conn) + if row is None: + return -2, "not found" + else: + return 0, {"item_name": row[0], "json_data": row[1]} + +# Function to create a new config item +def create_config_item(config_item: ConfigItem): + conn = pool.get_connection() + try: + try: + cursor = conn.cursor() + cursor.execute('INSERT INTO config_table (item_name, json_data) VALUES (?, ?)', (config_item.item_name, config_item.json_data)) + item_id = cursor.lastrowid + conn.commit() + print(item_id) + finally: + pool.release_connection(conn) + + return 0, {"id": item_id, "item_name":config_item.item_name, "json_data":config_item.json_data} + except Exception as e: + return -2, str(e) + +# Function to update a config item by ID +def update_config_item(item_id, config_item: ConfigItem): + conn = pool.get_connection() + try: + try: + cursor = conn.cursor() + cursor.execute('UPDATE config_table SET item_name = ?, json_data = ? WHERE id = ?', (config_item.item_name, config_item.json_data, item_id)) + conn.commit() + finally: + pool.release_connection(conn) + return 0, {"id": item_id, **config_item.dict()} + except Exception as e: + return -2, str(e) + +# Function to delete a config item by ID +def delete_config_item(item_id): + conn = pool.get_connection() + try: + cursor = conn.cursor() + cursor.execute('DELETE FROM config_table WHERE id = ?', (item_id,)) + conn.commit() + finally: + pool.release_connection(conn) + return 0, {"id": item_id} + +# endregion + +#Example of using config directive +# config_directive = "overrides" +# ret, res = get_config_item_by_name(config_directive) +# if ret < 0: +# print(f"CONFIG OVERRIDE {config_directive} Error {res}") +# else: +# config = orjson.loads(res["json_data"]) + +# print("OVERRIDN CFG:", config) +# for key, value in config.items(): +# if hasattr(cfg, key): +# print(f"Overriding {key} with {value}") +# setattr(cfg, key, value) + diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index b48ece9..3bb197a 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -1851,95 +1851,6 @@ def delete_indicator_byName(id: UUID, indicator: InstantIndicator): print(str(e) + format_exc()) return -2, str(e) -# region CONFIG db services -#TODO vytvorit modul pro dotahovani z pythonu (get_from_config(var_name, def_value) {)- stejne jako v js -#TODO zvazit presunuti do TOML z JSONu -def get_all_config_items(): - conn = pool.get_connection() - try: - cursor = conn.cursor() - cursor.execute('SELECT id, item_name, json_data FROM config_table') - config_items = [{"id": row[0], "item_name": row[1], "json_data": row[2]} for row in cursor.fetchall()] - finally: - pool.release_connection(conn) - return 0, config_items - -# Function to get a config item by ID -def get_config_item_by_id(item_id): - conn = pool.get_connection() - try: - cursor = conn.cursor() - cursor.execute('SELECT item_name, json_data FROM config_table WHERE id = ?', (item_id,)) - row = cursor.fetchone() - finally: - pool.release_connection(conn) - if row is None: - return -2, "not found" - else: - return 0, {"item_name": row[0], "json_data": row[1]} - -# Function to get a config item by ID -def get_config_item_by_name(item_name): - #print(item_name) - conn = pool.get_connection() - try: - cursor = conn.cursor() - query = f"SELECT item_name, json_data FROM config_table WHERE item_name = '{item_name}'" - #print(query) - cursor.execute(query) - row = cursor.fetchone() - #print(row) - finally: - pool.release_connection(conn) - if row is None: - return -2, "not found" - else: - return 0, {"item_name": row[0], "json_data": row[1]} - -# Function to create a new config item -def create_config_item(config_item: ConfigItem): - conn = pool.get_connection() - try: - try: - cursor = conn.cursor() - cursor.execute('INSERT INTO config_table (item_name, json_data) VALUES (?, ?)', (config_item.item_name, config_item.json_data)) - item_id = cursor.lastrowid - conn.commit() - print(item_id) - finally: - pool.release_connection(conn) - - return 0, {"id": item_id, "item_name":config_item.item_name, "json_data":config_item.json_data} - except Exception as e: - return -2, str(e) - -# Function to update a config item by ID -def update_config_item(item_id, config_item: ConfigItem): - conn = pool.get_connection() - try: - try: - cursor = conn.cursor() - cursor.execute('UPDATE config_table SET item_name = ?, json_data = ? WHERE id = ?', (config_item.item_name, config_item.json_data, item_id)) - conn.commit() - finally: - pool.release_connection(conn) - return 0, {"id": item_id, **config_item.dict()} - except Exception as e: - return -2, str(e) - -# Function to delete a config item by ID -def delete_config_item(item_id): - conn = pool.get_connection() - try: - cursor = conn.cursor() - cursor.execute('DELETE FROM config_table WHERE id = ?', (item_id,)) - conn.commit() - finally: - pool.release_connection(conn) - return 0, {"id": item_id} - -# endregion - #returns b def get_alpaca_history_bars(symbol: str, datetime_object_from: datetime, datetime_object_to: datetime, timeframe: TimeFrame): """Returns Bar object @@ -1990,4 +1901,11 @@ def get_alpaca_history_bars(symbol: str, datetime_object_from: datetime, datetim # change_archived_runner # delete_archived_runner_details - +#Example of using config directive +# config_directive = "python" +# ret, res = get_config_item_by_name(config_directive) +# if ret < 0: +# print(f"Error {res}") +# else: +# config = orjson.loads(res["json_data"]) +# print(config) \ No newline at end of file diff --git a/v2realbot/main.py b/v2realbot/main.py index 70c8f8a..fe35f46 100644 --- a/v2realbot/main.py +++ b/v2realbot/main.py @@ -10,6 +10,7 @@ from fastapi.security import APIKeyHeader import uvicorn from uuid import UUID import v2realbot.controller.services as cs +import v2realbot.controller.configs as cf from v2realbot.utils.ilog import get_log_window from v2realbot.common.model import RunManagerRecord, StrategyInstance, RunnerView, RunRequest, Trade, RunArchive, RunArchiveView, RunArchiveViewPagination, RunArchiveDetail, Bar, RunArchiveChange, TestList, ConfigItem, InstantIndicator, DataTablesRequest, AnalyzerInputs from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status, WebSocketException, Cookie, Query @@ -771,7 +772,7 @@ def delete_testlist(record_id: str): # Get all config items @app.get("/config-items/", dependencies=[Depends(api_key_auth)]) def get_all_items() -> list[ConfigItem]: - res, sada = cs.get_all_config_items() + res, sada = cf.get_all_config_items() if res == 0: return sada else: @@ -781,7 +782,7 @@ def get_all_items() -> list[ConfigItem]: # Get a config item by ID @app.get("/config-items/{item_id}", dependencies=[Depends(api_key_auth)]) def get_item(item_id: int)-> ConfigItem: - res, sada = cs.get_config_item_by_id(item_id) + res, sada = cf.get_config_item_by_id(item_id) if res == 0: return sada else: @@ -790,7 +791,7 @@ def get_item(item_id: int)-> ConfigItem: # Get a config item by Name @app.get("/config-items-by-name/", dependencies=[Depends(api_key_auth)]) def get_item(item_name: str)-> ConfigItem: - res, sada = cs.get_config_item_by_name(item_name) + res, sada = cf.get_config_item_by_name(item_name) if res == 0: return sada else: @@ -799,7 +800,7 @@ def get_item(item_name: str)-> ConfigItem: # Create a new config item @app.post("/config-items/", dependencies=[Depends(api_key_auth)], status_code=status.HTTP_200_OK) def create_item(config_item: ConfigItem) -> ConfigItem: - res, sada = cs.create_config_item(config_item) + res, sada = cf.create_config_item(config_item) if res == 0: return sada else: raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Error not created: {res}:{id} {sada}") @@ -808,7 +809,7 @@ def create_item(config_item: ConfigItem) -> ConfigItem: # Update a config item by ID @app.put("/config-items/{item_id}", dependencies=[Depends(api_key_auth)]) def update_item(item_id: int, config_item: ConfigItem) -> ConfigItem: - res, sada = cs.get_config_item_by_id(item_id) + res, sada = cf.get_config_item_by_id(item_id) if res != 0: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"No data found") @@ -821,11 +822,11 @@ def update_item(item_id: int, config_item: ConfigItem) -> ConfigItem: # Delete a config item by ID @app.delete("/config-items/{item_id}", dependencies=[Depends(api_key_auth)]) def delete_item(item_id: int) -> dict: - res, sada = cs.get_config_item_by_id(item_id) + res, sada = cf.get_config_item_by_id(item_id) if res != 0: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"No data found") - res, sada = cs.delete_config_item(item_id) + res, sada = cf.delete_config_item(item_id) if res == 0: return sada else: raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Error not created: {res}:{id}")