Feature/market attribute (#185)

* RunManagerRecord class has a new attribute market. Market enum is imported.

* row_to_runmanager function considers market column

* add_run_manager_record and update_run_manager_record functions are changed. fetch_all_markets_in_run_manager is new.

* new Market enumeration class is defined

* market_value used for job scheduling. start and stop functions have modifications of market parameter input

* new is_market_day function + modifications of get_todays_market_times function

* market attribute set default to US

* row_to_runmanager function has no string formatter for market attribute

* add_run_manager_record function adn update_run_manager_record function update the DB column market based on record.market data

* start_runman_record and stop_runman_record have got no market parameter

* get_todays_market_times function is changed

* default value for market atribute is Market.US

* update_run_manager_record function has no if condition for market key

* market_value deleted, used enumaration value Market.US instead of string US

* get_todays_market_times has a new if condition for Market.CRYPTO

* update includes market column in the run_manager table

* market attribute in Run Manager record has value given by enumeration as Market.US

* documentation of changes made in the branch

* remove README_feature_market.md

* back to original state

* Delete README_feature_market.md

* _start_runman_record has an additional else condition

* is_market_day renamed to is_US_market_day

* transferables column added into runner_header table
This commit is contained in:
pvlasak
2024-04-17 12:14:01 +02:00
committed by GitHub
parent 074b6feaf8
commit 8f87764fc9
7 changed files with 151 additions and 34 deletions

View File

@ -5,7 +5,7 @@ from rich import print
from typing import Any, Optional, List, Union
from datetime import datetime, date
from pydantic import BaseModel, Field
from v2realbot.enums.enums import Mode, Account, SchedulerStatus, Moddus
from v2realbot.enums.enums import Mode, Account, SchedulerStatus, Moddus, Market
from alpaca.data.enums import Exchange
@ -159,6 +159,7 @@ class RunManagerRecord(BaseModel):
mode: Mode
note: Optional[str] = None
ilog_save: bool = False
market: Optional[Market] = Market.US
bt_from: Optional[datetime] = None
bt_to: Optional[datetime] = None
#weekdays filter

View File

@ -5,9 +5,7 @@ import v2realbot.controller.services as cs
#prevede dict radku zpatky na objekt vcetme retypizace
def row_to_runmanager(row: dict) -> RunManagerRecord:
is_running = cs.is_runner_running(row['runner_id']) if row['runner_id'] else False
res = RunManagerRecord(
moddus=row['moddus'],
id=row['id'],
@ -17,6 +15,7 @@ def row_to_runmanager(row: dict) -> RunManagerRecord:
account=row['account'],
note=row['note'],
ilog_save=bool(row['ilog_save']),
market=row['market'] if row['market'] is not None else None,
bt_from=datetime.fromisoformat(row['bt_from']) if row['bt_from'] else None,
bt_to=datetime.fromisoformat(row['bt_to']) if row['bt_to'] else None,
weekdays_filter=[int(x) for x in row['weekdays_filter'].split(',')] if row['weekdays_filter'] else [],

View File

@ -172,14 +172,14 @@ def add_run_manager_record(new_record: RunManagerRecord):
# Construct a suitable INSERT query based on your RunManagerRecord fields
insert_query = """
INSERT INTO run_manager (moddus, id, strat_id, symbol,account, mode, note,ilog_save,
bt_from, bt_to, weekdays_filter, batch_id,
market, bt_from, bt_to, weekdays_filter, batch_id,
start_time, stop_time, status, last_processed,
history, valid_from, valid_to, testlist_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
"""
values = [
new_record.moddus, str(new_record.id), str(new_record.strat_id), new_record.symbol, new_record.account, new_record.mode, new_record.note,
int(new_record.ilog_save),
int(new_record.ilog_save), new_record.market,
new_record.bt_from.isoformat() if new_record.bt_from is not None else None,
new_record.bt_to.isoformat() if new_record.bt_to is not None else None,
",".join(str(x) for x in new_record.weekdays_filter) if new_record.weekdays_filter else None,

View File

@ -103,4 +103,10 @@ class StartBarAlign(str, Enum):
RANDOM = first bar starts when first trade occurs
"""
ROUND = "round"
RANDOM = "random"
RANDOM = "random"
class Market(str, Enum):
US = "US"
CRYPTO = "CRYPTO"

View File

@ -2,7 +2,7 @@ from uuid import UUID
from typing import Any, List, Tuple
from uuid import UUID, uuid4
from v2realbot.enums.enums import Moddus, SchedulerStatus, RecordType, StartBarAlign, Mode, Account, OrderSide
from v2realbot.common.model import RunManagerRecord, StrategyInstance, RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveViewPagination, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem, InstantIndicator, DataTablesRequest
from v2realbot.common.model import RunManagerRecord, StrategyInstance, RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveViewPagination, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem, InstantIndicator, DataTablesRequest, Market
from v2realbot.utils.utils import validate_and_format_time, AttributeDict, zoneNY, zonePRG, safe_get, dict_replace_value, Store, parse_toml_string, json_serial, is_open_hours, send_to_telegram, concatenate_weekdays, transform_data
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
from datetime import datetime
@ -116,7 +116,8 @@ def initialize_jobs(run_manager_records: RunManagerRecord = None):
scheduler.add_job(start_runman_record, start_trigger, id=f"scheduler_start_{record.id}", args=[record.id])
scheduler.add_job(stop_runman_record, stop_trigger, id=f"scheduler_stop_{record.id}", args=[record.id])
#scheduler.add_job(print_hello, 'interval', seconds=10, id=f"scheduler_testinterval")
#scheduler.add_job(print_hello, 'interval', seconds=10, id=
# f"scheduler_testinterval")
scheduled_jobs = scheduler.get_jobs()
print(f"APS jobs refreshed ({len(scheduled_jobs)})")
current_jobs_dict = format_apscheduler_jobs(scheduled_jobs)
@ -124,9 +125,9 @@ def initialize_jobs(run_manager_records: RunManagerRecord = None):
return 0, current_jobs_dict
#zastresovaci funkce resici error handling a printing
def start_runman_record(id: UUID, market = "US", debug_date = None):
def start_runman_record(id: UUID, debug_date = None):
record = None
res, record, msg = _start_runman_record(id=id, market=market, debug_date=debug_date)
res, record, msg = _start_runman_record(id=id, debug_date=debug_date)
if record is not None:
market_time_now = datetime.now().astimezone(zoneNY) if debug_date is None else debug_date
@ -165,8 +166,8 @@ def update_runman_record(record: RunManagerRecord):
err_msg= f"STOP: Error updating {record.id} errir {set} with values {record}"
return -2, err_msg#toto stopne zpracovani dalsich zaznamu pri chybe, zvazit continue
def stop_runman_record(id: UUID, market = "US", debug_date = None):
res, record, msg = _stop_runman_record(id=id, market=market, debug_date=debug_date)
def stop_runman_record(id: UUID, debug_date = None):
res, record, msg = _stop_runman_record(id=id, debug_date=debug_date)
#results : 0 - ok, -1 not running/already running/not specific, -2 error
#report vzdy zapiseme do history, pokud je record not None, pripadna chyba se stala po dotazeni recordu
@ -196,7 +197,7 @@ def stop_runman_record(id: UUID, market = "US", debug_date = None):
print(f"STOP JOB: {id} FINISHED")
#start function that is called from the job
def _start_runman_record(id: UUID, market = "US", debug_date = None):
def _start_runman_record(id: UUID, debug_date = None):
print(f"Start scheduled record {id}")
record : RunManagerRecord = None
@ -207,15 +208,16 @@ def _start_runman_record(id: UUID, market = "US", debug_date = None):
record = result
if market is not None and market == "US":
res, sada = sch.get_todays_market_times(market=market, debug_date=debug_date)
if record.market == Market.US or record.market == Market.CRYPTO:
res, sada = sch.get_todays_market_times(market=record.market, debug_date=debug_date)
if res == 0:
market_time_now, market_open_datetime, market_close_datetime = sada
print(f"OPEN:{market_open_datetime} CLOSE:{market_close_datetime}")
else:
sada = f"Market {market} Error getting market times (CLOSED): " + str(sada)
sada = f"Market {record.market} Error getting market times (CLOSED): " + str(sada)
return res, record, sada
else:
print("Market type is unknown.")
if cs.is_stratin_running(record.strat_id):
return -1, record, f"Stratin {record.strat_id} is already running"
@ -229,7 +231,7 @@ def _start_runman_record(id: UUID, market = "US", debug_date = None):
return 0, record, record.runner_id
#stop function that is called from the job
def _stop_runman_record(id: UUID, market = "US", debug_date = None):
def _stop_runman_record(id: UUID, debug_date = None):
record = None
#get all records
print(f"Stopping record {id}")
@ -304,5 +306,5 @@ if __name__ == "__main__":
# print(f"CALL FINISHED, with {debug_date} RESULT: {res}, {result}")
res, result = stop_runman_record(id=id, market = "US", debug_date = debug_date)
res, result = stop_runman_record(id=id, debug_date = debug_date)
print(f"CALL FINISHED, with {debug_date} RESULT: {res}, {result}")

View File

@ -2,10 +2,10 @@ import json
import datetime
import v2realbot.controller.services as cs
import v2realbot.controller.run_manager as rm
from v2realbot.common.model import RunnerView, RunManagerRecord, StrategyInstance, Runner, RunRequest, Trade, RunArchive, RunArchiveView, RunArchiveViewPagination, RunArchiveDetail, Bar, RunArchiveChange, TestList, ConfigItem, InstantIndicator, DataTablesRequest, AnalyzerInputs
from v2realbot.common.model import RunnerView, RunManagerRecord, StrategyInstance, Runner, RunRequest, Trade, RunArchive, RunArchiveView, RunArchiveViewPagination, RunArchiveDetail, Bar, RunArchiveChange, TestList, ConfigItem, InstantIndicator, DataTablesRequest, AnalyzerInputs, Market
from uuid import uuid4, UUID
from v2realbot.utils.utils import json_serial, send_to_telegram, zoneNY, zonePRG, fetch_calendar_data
from datetime import datetime, timedelta
from v2realbot.utils.utils import json_serial, send_to_telegram, zoneNY, zonePRG, zoneUTC, fetch_calendar_data
from datetime import datetime, timedelta, time
from traceback import format_exc
from rich import print
import requests
@ -18,9 +18,18 @@ from v2realbot.config import WEB_API_KEY
#naplanovany jako samostatni job a triggerován pouze jednou v daný čas pro start a stop
#novy kod v aps_scheduler.py
def get_todays_market_times(market = "US", debug_date = None):
def is_US_market_day(date):
cal_dates = fetch_calendar_data(date, date)
if len(cal_dates) == 0:
print("Today is not a market day.")
return False, cal_dates
else:
print("Market is open")
return True, cal_dates
def get_todays_market_times(market, debug_date = None):
try:
if market == "US":
if market == Market.US:
#zjistit vsechny podminky - mozna loopovat - podminky jsou vlevo
if debug_date is not None:
nowNY = debug_date
@ -28,17 +37,20 @@ def get_todays_market_times(market = "US", debug_date = None):
nowNY = datetime.now().astimezone(zoneNY)
nowNY_date = nowNY.date()
#is market open - nyni pouze US
cal_dates = fetch_calendar_data(nowNY_date, nowNY_date)
if len(cal_dates) == 0:
print("No Market Day today")
return -1, "Market Closed"
stat, calendar_dates = is_US_market_day(nowNY_date)
if stat:
#zatim podpora pouze main session
#pouze main session
market_open_datetime = zoneNY.localize(cal_dates[0].open)
market_close_datetime = zoneNY.localize(cal_dates[0].close)
return 0, (nowNY, market_open_datetime, market_close_datetime)
market_open_datetime = zoneNY.localize(calendar_dates[0].open)
market_close_datetime = zoneNY.localize(calendar_dates[0].close)
return 0, (nowNY, market_open_datetime, market_close_datetime)
else:
return -1, "Market is closed."
elif market == Market.CRYPTO:
now_market_datetime = datetime.now().astimezone(zoneUTC)
market_open_datetime = datetime.combine(datetime.now(), time.min)
matket_close_datetime = datetime.combine(datetime.now(), time.max)
return 0, (now_market_datetime, market_open_datetime, matket_close_datetime)
else:
return -1, "Market not supported"
except Exception as e:

97
v2trading_create_db.sql Normal file
View File

@ -0,0 +1,97 @@
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "test_list" (
"id" varchar(32) NOT NULL,
"name" varchar(255) NOT NULL,
"dates" json NOT NULL
);
CREATE TABLE IF NOT EXISTS "runner_detail" (
"runner_id" varchar(32) NOT NULL,
"data" json NOT NULL,
PRIMARY KEY("runner_id")
);
CREATE TABLE IF NOT EXISTS "runner_header" (
"runner_id" varchar(32) NOT NULL,
"strat_id" TEXT,
"batch_id" TEXT,
"symbol" TEXT,
"name" TEXT,
"note" TEXT,
"started" TEXT,
"stopped" TEXT,
"mode" TEXT,
"account" TEXT,
"bt_from" TEXT,
"bt_to" TEXT,
"strat_json" TEXT,
"settings" TEXT,
"ilog_save" INTEGER,
"profit" NUMERIC,
"trade_count" INTEGER,
"end_positions" INTEGER,
"end_positions_avgp" NUMERIC,
"metrics" TEXT,
"stratvars_toml" TEXT,
"transferables" TEXT,
PRIMARY KEY("runner_id")
);
CREATE TABLE IF NOT EXISTS "config_table" (
"id" INTEGER,
"item_name" TEXT NOT NULL,
"json_data" JSON NOT NULL,
"item_lang" TEXT,
PRIMARY KEY("id" AUTOINCREMENT)
);
CREATE TABLE IF NOT EXISTS "runner_logs" (
"runner_id" varchar(32) NOT NULL,
"time" real NOT NULL,
"data" json NOT NULL
);
CREATE TABLE "run_manager" (
"moddus" TEXT NOT NULL,
"id" varchar(32),
"strat_id" varchar(32) NOT NULL,
"symbol" TEXT,
"account" TEXT NOT NULL,
"mode" TEXT NOT NULL,
"note" TEXT,
"ilog_save" BOOLEAN,
"bt_from" TEXT,
"bt_to" TEXT,
"weekdays_filter" TEXT,
"batch_id" TEXT,
"start_time" TEXT NOT NULL,
"stop_time" TEXT NOT NULL,
"status" TEXT NOT NULL,
"last_processed" TEXT,
"history" TEXT,
"valid_from" TEXT,
"valid_to" TEXT,
"testlist_id" TEXT,
"runner_id" varchar2(32),
"market" TEXT,
PRIMARY KEY("id")
);
CREATE INDEX idx_moddus ON run_manager (moddus);
CREATE INDEX idx_status ON run_manager (status);
CREATE INDEX idx_status_moddus ON run_manager (status, moddus);
CREATE INDEX idx_valid_from_to ON run_manager (valid_from, valid_to);
CREATE INDEX idx_stopped_batch_id ON runner_header (stopped, batch_id);
CREATE INDEX idx_search_value ON runner_header (strat_id, batch_id);
CREATE INDEX IF NOT EXISTS "index_runner_header_pk" ON "runner_header" (
"runner_id"
);
CREATE INDEX IF NOT EXISTS "index_runner_header_strat" ON "runner_header" (
"strat_id"
);
CREATE INDEX IF NOT EXISTS "index_runner_header_batch" ON "runner_header" (
"batch_id"
);
CREATE UNIQUE INDEX IF NOT EXISTS "index_runner_detail_pk" ON "runner_detail" (
"runner_id"
);
CREATE INDEX IF NOT EXISTS "index_runner_logs" ON "runner_logs" (
"runner_id",
"time"
);
INSERT INTO config_table VALUES (1, "test", "{}", "json");
COMMIT;