From 855e4379a356eb2de2060a46eedf1630051f3853 Mon Sep 17 00:00:00 2001 From: David Brazda Date: Fri, 23 Feb 2024 12:35:02 +0700 Subject: [PATCH] #139 konfigurace LIVE_DATA_FEED --- v2realbot/config.py | 81 +++++++++++++++++++++++---- v2realbot/controller/run_manager.py | 7 --- v2realbot/controller/services.py | 6 +- v2realbot/loader/trade_ws_streamer.py | 5 +- v2realbot/utils/historicals.py | 4 +- 5 files changed, 79 insertions(+), 24 deletions(-) diff --git a/v2realbot/config.py b/v2realbot/config.py index 4487e69..7a13a0f 100644 --- a/v2realbot/config.py +++ b/v2realbot/config.py @@ -108,7 +108,8 @@ class Keys: self.FEED = feed # podle modu (PAPER, LIVE) vrati objekt -# obsahujici klice pro pripojeni k alpace +# obsahujici klice pro pripojeni k alpace - používá se pro Trading API a order updates websockets (pristupy relevantni per strategie) +#pro real time data se bere LIVE_DATA_API_KEY, LIVE_DATA_SECRET_KEY, LIVE_DATA_FEED nize - jelikoz jde o server wide nastaveni def get_key(mode: Mode, account: Account): if mode not in [Mode.PAPER, Mode.LIVE]: print("has to be LIVE or PAPER only") @@ -134,28 +135,88 @@ ACCOUNT1_PAPER_API_KEY = os.environ.get('ACCOUNT1_PAPER_API_KEY') ACCOUNT1_PAPER_SECRET_KEY = os.environ.get('ACCOUNT1_PAPER_SECRET_KEY') ACCOUNT1_PAPER_MAX_BATCH_SIZE = 1 ACCOUNT1_PAPER_PAPER = True -ACCOUNT1_PAPER_FEED = DataFeed.SIP +#ACCOUNT1_PAPER_FEED = DataFeed.SIP + +# Load the data feed type from environment variable +data_feed_type_str = os.environ.get('ACCOUNT1_PAPER_FEED', 'iex') # Default to 'sip' if not set + +# Convert the string to DataFeed enum +try: + ACCOUNT1_PAPER_FEED = DataFeed(data_feed_type_str) +except ValueError: + # Handle the case where the environment variable does not match any enum member + print(f"Invalid data feed type: {data_feed_type_str} in ACCOUNT1_PAPER_FEED defaulting to 'iex'") + ACCOUNT1_PAPER_FEED = DataFeed.SIP #PRIMARY LIVE ACCOUNT1_LIVE_API_KEY = os.environ.get('ACCOUNT1_LIVE_API_KEY') ACCOUNT1_LIVE_SECRET_KEY = os.environ.get('ACCOUNT1_LIVE_SECRET_KEY') ACCOUNT1_LIVE_MAX_BATCH_SIZE = 1 ACCOUNT1_LIVE_PAPER = False -ACCOUNT1_LIVE_FEED = DataFeed.SIP +#ACCOUNT1_LIVE_FEED = DataFeed.SIP + +# Load the data feed type from environment variable +data_feed_type_str = os.environ.get('ACCOUNT1_LIVE_FEED', 'iex') # Default to 'sip' if not set + +# Convert the string to DataFeed enum +try: + ACCOUNT1_LIVE_FEED = DataFeed(data_feed_type_str) +except ValueError: + # Handle the case where the environment variable does not match any enum member + print(f"Invalid data feed type: {data_feed_type_str} in ACCOUNT1_LIVE_FEED defaulting to 'iex'") + ACCOUNT1_LIVE_FEED = DataFeed.IEX #SECONDARY PAPER - Martin ACCOUNT2_PAPER_API_KEY = os.environ.get('ACCOUNT2_PAPER_API_KEY') ACCOUNT2_PAPER_SECRET_KEY = os.environ.get('ACCOUNT2_PAPER_SECRET_KEY') ACCOUNT2_PAPER_MAX_BATCH_SIZE = 1 ACCOUNT2_PAPER_PAPER = True -ACCOUNT2_PAPER_FEED = DataFeed.IEX +#ACCOUNT2_PAPER_FEED = DataFeed.IEX -# #SECONDARY PAPER -# ACCOUNT2_PAPER_API_KEY = 'PK0OQHZG03PUZ1SC560V' -# ACCOUNT2_PAPER_SECRET_KEY = 'cTglhm7kwRcZfFT27fQWz31sXaxadzQApFDW6Lat' -# ACCOUNT2_PAPER_MAX_BATCH_SIZE = 1 -# ACCOUNT2_PAPER_PAPER = True -# ACCOUNT2_PAPER_FEED = DataFeed.IEX +# Load the data feed type from environment variable +data_feed_type_str = os.environ.get('ACCOUNT2_PAPER_FEED', 'iex') # Default to 'sip' if not set + +# Convert the string to DataFeed enum +try: + ACCOUNT2_PAPER_FEED = DataFeed(data_feed_type_str) +except ValueError: + # Handle the case where the environment variable does not match any enum member + print(f"Invalid data feed type: {data_feed_type_str} in ACCOUNT2_PAPER_FEED defaulting to 'iex'") + ACCOUNT2_PAPER_FEED = DataFeed.IEX + + +#SECONDARY LIVE - Martin +# ACCOUNT2_LIVE_API_KEY = os.environ.get('ACCOUNT2_LIVE_API_KEY') +# ACCOUNT2_LIVE_SECRET_KEY = os.environ.get('ACCOUNT2_LIVE_SECRET_KEY') +# ACCOUNT2_LIVE_MAX_BATCH_SIZE = 1 +# ACCOUNT2_LIVE_PAPER = True +# #ACCOUNT2_LIVE_FEED = DataFeed.IEX + +# # Load the data feed type from environment variable +# data_feed_type_str = os.environ.get('ACCOUNT2_LIVE_FEED', 'iex') # Default to 'sip' if not set + +# # Convert the string to DataFeed enum +# try: +# ACCOUNT2_LIVE_FEED = DataFeed(data_feed_type_str) +# except ValueError: +# # Handle the case where the environment variable does not match any enum member +# print(f"Invalid data feed type: {data_feed_type_str} in ACCOUNT2_LIVE_FEED defaulting to 'iex'") +# ACCOUNT2_LIVE_FEED = DataFeed.IEX + +#zatim jsou LIVE_DATA nastaveny jako z account1_paper +LIVE_DATA_API_KEY = ACCOUNT1_PAPER_API_KEY +LIVE_DATA_SECRET_KEY = ACCOUNT1_PAPER_SECRET_KEY + +# Load the data feed type from environment variable +data_feed_type_str = os.environ.get('LIVE_DATA_FEED', 'iex') # Default to 'sip' if not set + +# Convert the string to DataFeed enum +try: + LIVE_DATA_FEED = DataFeed(data_feed_type_str) +except ValueError: + # Handle the case where the environment variable does not match any enum member + print(f"Invalid data feed type: {data_feed_type_str} in LIVE_DATA_FEED defaulting to 'iex'") + LIVE_DATA_FEED = DataFeed.IEX class KW: activate: str = "activate" diff --git a/v2realbot/controller/run_manager.py b/v2realbot/controller/run_manager.py index 560177c..7ece32c 100644 --- a/v2realbot/controller/run_manager.py +++ b/v2realbot/controller/run_manager.py @@ -1,12 +1,5 @@ from typing import Any, List, Tuple from uuid import UUID, uuid4 -import pickle -from alpaca.data.historical import StockHistoricalDataClient -from alpaca.data.requests import StockTradesRequest, StockBarsRequest -from alpaca.data.enums import DataFeed -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 RunManagerRecord, StrategyInstance, RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveViewPagination, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem, InstantIndicator, DataTablesRequest 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.utils.ilog import delete_logs diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index 790143d..368e3d7 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -14,7 +14,7 @@ from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeSt from datetime import datetime from v2realbot.loader.trade_offline_streamer import Trade_Offline_Streamer from threading import Thread, current_thread, Event, enumerate -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, OFFLINE_MODE +from v2realbot.config import STRATVARS_UNCHANGEABLES, ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, ACCOUNT1_PAPER_FEED, ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, ACCOUNT1_LIVE_FEED, 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, OFFLINE_MODE import importlib from alpaca.trading.requests import GetCalendarRequest from alpaca.trading.client import TradingClient @@ -717,7 +717,7 @@ def get_trade_history(symbol: str, timestamp_from: float, timestamp_to:float): #datetime_object_from = datetime(2023, 4, 14, 15, 51, 38, tzinfo=zoneNY) #datetime_object_to = datetime(2023, 4, 14, 15, 51, 39, tzinfo=zoneNY) client = StockHistoricalDataClient(ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, raw_data=False) - trades_request = StockTradesRequest(symbol_or_symbols=symbol, feed = DataFeed.SIP, start=datetime_object_from, end=datetime_object_to) + trades_request = StockTradesRequest(symbol_or_symbols=symbol, feed = ACCOUNT1_LIVE_FEED, start=datetime_object_from, end=datetime_object_to) all_trades = client.get_stock_trades(trades_request) #print(all_trades[symbol]) return 0, all_trades[symbol] @@ -1947,7 +1947,7 @@ def get_alpaca_history_bars(symbol: str, datetime_object_from: datetime, datetim client = StockHistoricalDataClient(ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, raw_data=False) #datetime_object_from = datetime(2023, 2, 27, 18, 51, 38, tzinfo=datetime.timezone.utc) #datetime_object_to = datetime(2023, 2, 27, 21, 51, 39, tzinfo=datetime.timezone.utc) - bar_request = StockBarsRequest(symbol_or_symbols=symbol,timeframe=timeframe, start=datetime_object_from, end=datetime_object_to, feed=DataFeed.SIP) + bar_request = StockBarsRequest(symbol_or_symbols=symbol,timeframe=timeframe, start=datetime_object_from, end=datetime_object_to, feed=ACCOUNT1_LIVE_API_KEY) #print("before df") bars = client.get_stock_bars(bar_request) result = [] diff --git a/v2realbot/loader/trade_ws_streamer.py b/v2realbot/loader/trade_ws_streamer.py index 961a585..2df97af 100644 --- a/v2realbot/loader/trade_ws_streamer.py +++ b/v2realbot/loader/trade_ws_streamer.py @@ -4,7 +4,7 @@ """ from v2realbot.loader.aggregator import TradeAggregator2Queue from alpaca.data.live import StockDataStream -from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, ACCOUNT1_PAPER_FEED +from v2realbot.config import LIVE_DATA_API_KEY, LIVE_DATA_SECRET_KEY, LIVE_DATA_FEED from alpaca.data.historical import StockHistoricalDataClient from alpaca.data.requests import StockLatestQuoteRequest, StockBarsRequest, StockTradesRequest from threading import Thread, current_thread @@ -21,7 +21,8 @@ from msgpack import packb class Trade_WS_Streamer(Thread): ##tento ws streamer je pouze jeden pro vsechny, tzn. vyuziváme natvrdo placena data primarniho uctu (nezalezi jestli paper nebo live) - client = StockDataStream(ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, raw_data=True, websocket_params={}, feed=ACCOUNT1_PAPER_FEED) + print(f"Realtime Websocket connection will use FEED: {LIVE_DATA_FEED} and credential of ACCOUNT1") + client = StockDataStream(LIVE_DATA_API_KEY, LIVE_DATA_SECRET_KEY, raw_data=True, websocket_params={}, feed=LIVE_DATA_FEED) #uniquesymbols = set() _streams = [] #to_run = dict() diff --git a/v2realbot/utils/historicals.py b/v2realbot/utils/historicals.py index e82e69a..aa8c150 100644 --- a/v2realbot/utils/historicals.py +++ b/v2realbot/utils/historicals.py @@ -4,7 +4,7 @@ from alpaca.data import Quote, Trade, Snapshot, Bar from alpaca.data.models import BarSet, QuoteSet, TradeSet from alpaca.data.timeframe import TimeFrame, TimeFrameUnit from v2realbot.utils.utils import zoneNY, send_to_telegram -from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY +from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, ACCOUNT1_PAPER_FEED from alpaca.data.enums import DataFeed from datetime import datetime, timedelta import pandas as pd @@ -112,7 +112,7 @@ def get_historical_bars(symbol: str, time_from: datetime, time_to: datetime, tim :raises: Exception if all retries fail. """ stock_client = StockHistoricalDataClient(ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, raw_data=True) - bar_request = StockBarsRequest(symbol_or_symbols=symbol, timeframe=timeframe, start=time_from, end=time_to, feed=DataFeed.SIP) + bar_request = StockBarsRequest(symbol_or_symbols=symbol, timeframe=timeframe, start=time_from, end=time_to, feed=ACCOUNT1_PAPER_FEED) last_exception = None