QuantConnect / lean-cli

CLI for running the LEAN engine locally and in the cloud
https://www.lean.io/cli
Apache License 2.0
194 stars 99 forks source link

Add support for different datafeed in cloud #359

Closed Marinovsky closed 12 months ago

Marinovsky commented 1 year ago

Closes #81

Description

So far just lean live deploy supports different datafeed. With this change, the method get_price_data_handler() from cloud_brokerage.py can now parse the datafeed selected in the user input to the expected name in the QC API. In order to make this, the file modules-1.11.json was also modified to accept one choice from the available datafeed's for certain brokerage. For example, for IB brokerage:

{
                    "id": "ib-data-feed",
                    "type": "input",
                    "value": "",
                    "filters": [
                        {
                            "condition": {
                                "type": "exact-match",
                                "pattern": "CloudBrokerage",
                                "dependent-config-id": "module-type"
                            }
                        }
                    ],
                    "input-method": "choice",
                    "input-choices": [
                        "QuantConnect",
                        "Interactive Brokers",
                        "QuantConnect + InteractiveBrokers"
                    ],
                    "prompt-info": "Which one do you want to use: the Interactive Brokers price data feed, QuantConnect price data feed or QuantConnect + InteractiveBrokers price data feed",
                    "help": "The available price data feeds are: Interactive Brokers price data feed, QuantConnect price data feed or QuantConnect + InteractiveBrokers price data feed"
                },

In the same way, the method get_price_data_handler() was modified to work for other brokerages in the future. Below, it's shown a unit test made to assert this:

@pytest.mark.parametrize("brokerage, datafeed, expected", [
                                                ("Binance", "Binance", "Binance"),
                                                ("Binance", "QuantConnect + Binance", "quantconnecthandler+binancehandler"),
                                                ("Bitfinex", "QuantConnect", "QuantConnect"),
                                                ("Bitfinex", "Bitfinex", "Bitfinex"),
                                                ("Bitfinex", "QuantConnect + Bitfinex", "quantconnecthandler+bitfinexhandler"),
                                                ("Coinbase Pro", "QuantConnect", "QuantConnect"),
                                                ("Coinbase Pro", "Coinbase Pro", "CoinbasePro"),
                                                ("Coinbase Pro", "QuantConnect + CoinbasePro", "quantconnecthandler+coinbaseprohandler"),
                                                ("Interactive Brokers", "QuantConnect", "QuantConnect"),
                                                ("Interactive Brokers", "Interactive Brokers", "InteractiveBrokers"),
                                                ("Interactive Brokers", "QuantConnect + InteractiveBrokers", "quantconnecthandler+interactivebrokershandler"),
                                                ("Kraken",  "QuantConnect", "QuantConnect"),
                                                ("Kraken", "Kraken", "Kraken"),
                                                ("Kraken", "QuantConnect + Kraken", "quantconnecthandler+krakenhandler"),
                                                ("OANDA",  "QuantConnect", "QuantConnect"),
                                                ("OANDA", "Oanda", "Oanda"),
                                                ("OANDA", "QuantConnect + Oanda", "quantconnecthandler+oandahandler"),
                                                ("Samco", "QuantConnect", "QuantConnect"),
                                                ("Samco", "Samco", "Samco"),
                                                ("Samco", "QuantConnect + Samco", "quantconnecthandler+samcohandler"),
                                                ("Tradier", "QuantConnect", "QuantConnect"),
                                                ("Tradier", "Tradier Brokerage", "TradierBrokerage"),
                                                ("Zerodha", "QuantConnect", "QuantConnect"),
                                                ("Zerodha", "Zerodha", "Zerodha"),
                                                ("Zerodha", "QuantConnect + Zerodha", "quantconnecthandler+zerodhahandler"),
                                                ("TDAmeritrade", "QuantConnect", "QuantConnect"),
                                                ("TDAmeritrade", "TDAmeritrade", "TDAmeritrade"),
                                                ("TDAmeritrade", "QuantConnect + TDAmeritrade", "quantconnecthandler+tdameritradehandler")])
def test_cloud_live_deploy_with_live_holdings(brokerage: str, datafeed: str, expected: str) -> None:
    create_fake_lean_cli_directory()

    cloud_project_manager = mock.Mock()
    container.cloud_project_manager = cloud_project_manager

    api_client = mock.Mock()
    api_client.nodes.get_all.return_value = create_qc_nodes()
    api_client.get.return_value = {'live': [], 'portfolio': {}}
    container.api_client = api_client

    cloud_runner = mock.Mock()
    container.cloud_runner = cloud_runner

    options = []
    for key, value in brokerage_required_options[brokerage].items():
        if "organization" not in key and key != "ib-enable-delayed-streaming-data":
            options.extend([f"--{key}", value])

    if brokerage == "Trading Technologies":
        options.extend(["--live-cash-balance", "USD:100"])
    elif brokerage == "Interactive Brokers":
        options.extend(["--ib-data-feed", datafeed])
    elif brokerage == "Tradier":
        options.extend(["--tradier-data-feed", datafeed])
    elif brokerage == "OANDA":
        options.extend(["--oanda-data-feed", datafeed])
    elif brokerage == "Binance":
        options.extend(["--binance-data-feed", datafeed])
    elif brokerage == "Bitfinex":
        options.extend(["--bitfinex-data-feed", datafeed])
    elif brokerage == "Coinbase Pro":
        options.extend(["--cp-data-feed", datafeed])
    elif brokerage == "Zerodha":
        options.extend(["--zerodha-data-feed", datafeed])
    elif brokerage == "Samco":
        options.extend(["--samco-data-feed", datafeed])
    elif brokerage == "Terminal Link":
        options.extend(["--tl-data-feed", datafeed])
    elif brokerage == "Kraken":
        options.extend(["--kraken-data-feed", datafeed])
    elif brokerage == "TDAmeritrade":
        options.extend(["--tdameritrade-data-feed", datafeed])

    result = CliRunner().invoke(lean, ["cloud", "live", "Python Project", "--brokerage", brokerage,
                                       "--node", "live", "--auto-restart", "yes", "--notify-order-events", "no",
                                       "--notify-insights", "no", *options])

    assert result.exit_code == 0
    assert f"Data provider: {expected}" in result.output.split("\n")

imagen Finally, unit tests for InteractiveBrokers and Tradier brokerages were made to cover these changes.