Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix backtest data provider configuration #403

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions lean/commands/live/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,13 @@ def _get_configurable_modules_from_environment(lean_config: Dict[str, Any], envi

brokerage = environment["live-mode-brokerage"]
data_queue_handlers = environment["data-queue-handler"]
[brokerage_configurer] = [local_brokerage for local_brokerage in all_local_brokerages if _get_brokerage_base_name(local_brokerage.get_live_name(environment_name)) == _get_brokerage_base_name(brokerage)]
[brokerage_configurer] = [local_brokerage
for local_brokerage in all_local_brokerages
if _get_brokerage_base_name(local_brokerage.get_live_name()) == _get_brokerage_base_name(brokerage)]
data_queue_handlers_base_names = [_get_brokerage_base_name(data_queue_handler) for data_queue_handler in data_queue_handlers]
data_feed_configurers = [local_data_feed for local_data_feed in all_local_data_feeds if _get_brokerage_base_name(local_data_feed.get_live_name(environment_name)) in data_queue_handlers_base_names]
data_feed_configurers = [local_data_feed
for local_data_feed in all_local_data_feeds
if _get_brokerage_base_name(local_data_feed.get_live_name()) in data_queue_handlers_base_names]
return brokerage_configurer, data_feed_configurers


Expand Down Expand Up @@ -335,7 +339,7 @@ def deploy(project: Path,
if environment is not None:
environment_name = environment
lean_config = lean_config_manager.get_complete_lean_config(environment_name, algorithm_file, None)

lean_environment = lean_config["environments"][environment_name]
for key in ["live-mode-brokerage", "data-queue-handler"]:
if key not in lean_environment:
Expand All @@ -362,7 +366,7 @@ def deploy(project: Path,
kwargs[property_name_to_fill] = property_value_to_fill
lean_config[condition._dependent_config_id] = property_value_to_fill
break

for local_data_feed in all_local_data_feeds:
configuration_environments: List[ConfigurationsEnvConfiguration] = [config for config in local_data_feed._lean_configs if config._is_type_configurations_env]
for configuration_environment in configuration_environments:
Expand Down
8 changes: 3 additions & 5 deletions lean/models/brokerages/local/data_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ class DataFeed(LeanConfigConfigurer):
def __init__(self, json_datafeed_data: Dict[str, Any]) -> None:
super().__init__(json_datafeed_data)

def get_live_name(self, environment_name: str) -> str:
def get_live_name(self) -> str:
live_name = self._id
environment_obj = self.get_configurations_env_values_from_name(
environment_name)
environment_obj = self.get_configurations_env_values()
if environment_obj:
[live_name] = [x["value"]
for x in environment_obj if x["name"] == "data-queue-handler"]
[live_name] = [x["value"] for x in environment_obj if x["name"] == "data-queue-handler"]
return live_name
8 changes: 3 additions & 5 deletions lean/models/brokerages/local/local_brokerage.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ class LocalBrokerage(LeanConfigConfigurer):
def __init__(self, json_brokerage_data: Dict[str, Any]) -> None:
super().__init__(json_brokerage_data)

def get_live_name(self, environment_name: str) -> str:
def get_live_name(self) -> str:
live_name = self._id
environment_obj = self.get_configurations_env_values_from_name(
environment_name)
environment_obj = self.get_configurations_env_values()
if environment_obj:
[live_name] = [x["value"]
for x in environment_obj if x["name"] == "live-mode-brokerage"]
[live_name] = [x["value"] for x in environment_obj if x["name"] == "live-mode-brokerage"]
return live_name
3 changes: 2 additions & 1 deletion lean/models/json_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,14 @@ def update_configs(self, key_and_values: Dict[str, str]):
for key, value in key_and_values.items():
self.update_value_for_given_config(key, value)

def get_configurations_env_values_from_name(self, target_env: str) -> List[Dict[str, str]]:
def get_configurations_env_values(self) -> List[Dict[str, str]]:
env_config_values = []
[env_config] = [config for config in self._lean_configs if
config._is_type_configurations_env and self.check_if_config_passes_filters(
config)
] or [None]
if env_config is not None:
# Always get the first one, since we only expect one env config in the json modules file
env_config_values = list(env_config._env_and_values.values())[0]
return env_config_values

Expand Down
4 changes: 1 addition & 3 deletions lean/models/lean_config_configurer.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def _configure_environment(self, lean_config: Dict[str, Any], environment_name:
:param lean_config: the Lean configuration dict to write to
:param environment_name: the name of the environment to update
"""
for environment_config in self.get_configurations_env_values_from_name(environment_name):
for environment_config in self.get_configurations_env_values():
environment_config_name = environment_config["name"]
if self.__class__.__name__ == 'DataFeed':
if environment_config_name == "data-queue-handler":
Expand All @@ -51,8 +51,6 @@ def _configure_environment(self, lean_config: Dict[str, Any], environment_name:
elif self.__class__.__name__ == 'LocalBrokerage':
if environment_config_name != "data-queue-handler":
lean_config["environments"][environment_name][environment_config_name] = environment_config["value"]
else:
raise ValueError(f'{self.__class__.__name__} not valid for _configure_environment()')

def configure_credentials(self, lean_config: Dict[str, Any]) -> None:
"""Configures the credentials in the Lean config for this brokerage and saves them persistently to disk.
Expand Down
123 changes: 123 additions & 0 deletions tests/models/test_lean_config_configurer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean CLI v1.0. Copyright 2021 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
from typing import Dict, Any
from unittest import mock

from lean.models.brokerages.local import DataFeed
from lean.models.data_providers import DataProvider
from lean.models.lean_config_configurer import LeanConfigConfigurer

JSON_MODULE = json.loads("""
{
"type": [
"data-queue-handler",
"data-provider"
],
"product-id": "305",
"id": "PolygonDataFeed",
"display-id": "Polygon",
"installs": true,
"configurations": [
{
"id": "polygon-api-key",
"cloud-id": "apiKey",
"type": "input",
"value": "",
"input-method": "prompt",
"prompt-info": "Your Polygon.io API Key",
"help": "Your Polygon.io API Key"
},
{
"id": "environments",
"type": "configurations-env",
"value": [
{
"name": "lean-cli",
"value": [
{
"name": "data-queue-handler",
"value": "QuantConnect.Polygon.PolygonDataQueueHandler"
},
{
"name": "history-provider",
"value": [
"QuantConnect.Polygon.PolygonDataQueueHandler",
"SubscriptionDataReaderHistoryProvider"
]
}
]
}
]
},
{
"id": "data-provider",
"type": "info",
"value": "QuantConnect.Lean.Engine.DataFeeds.DownloaderDataProvider"
},
{
"id": "data-downloader",
"type": "info",
"value": "QuantConnect.Polygon.PolygonDataDownloader"
}
]
}
""")


def test_gets_environment_from_configuration() -> None:
module = LeanConfigConfigurer(JSON_MODULE)
environment_values = module.get_configurations_env_values()

assert environment_values == JSON_MODULE["configurations"][1]["value"][0]["value"]


def get_lean_config() -> Dict[str, Any]:
return {
"environments": {
"live-ib-polygon": {
"live-mode": True,
"live-mode-brokerage": "InteractiveBrokersBrokerage",
"setup-handler": "QuantConnect.Lean.Engine.Setup.BrokerageSetupHandler",
"result-handler": "QuantConnect.Lean.Engine.Results.LiveTradingResultHandler",
"data-feed-handler": "QuantConnect.Lean.Engine.DataFeeds.LiveTradingDataFeed",
"data-queue-handler": ["QuantConnect.Brokerages.InteractiveBrokers.InteractiveBrokersBrokerage"],
"real-time-handler": "QuantConnect.Lean.Engine.RealTime.LiveTradingRealTimeHandler",
"transaction-handler": "QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler",
"history-provider": [
"BrokerageHistoryProvider",
"SubscriptionDataReaderHistoryProvider"
]
}
}
}


def test_configures_environment_with_module() -> None:
with mock.patch.object(DataFeed, "configure_credentials"):
lean_config = get_lean_config()
module = DataFeed(JSON_MODULE)
module.configure(lean_config, "live-ib-polygon")

assert lean_config != get_lean_config()
assert "QuantConnect.Polygon.PolygonDataQueueHandler" in lean_config["environments"]["live-ib-polygon"]["data-queue-handler"]


def test_invalid_environment_configuration_is_ignored() -> None:
with mock.patch.object(DataProvider, "configure_credentials"):
lean_config = get_lean_config()
module = DataProvider(JSON_MODULE)
module.configure(lean_config, "live-ib-polygon")

assert lean_config == get_lean_config()
Loading