Skip to content

Commit

Permalink
Merge pull request #59 from AdalyatNazirov/feature-ftxus-brokerage-su…
Browse files Browse the repository at this point in the history
…pport

Support FTX.US brokerage in lean cli
  • Loading branch information
Martin-Molinero authored Jan 26, 2022
2 parents 3574479 + 541909f commit 0e989b3
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 40 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ Options:
--binance-api-secret TEXT Your Binance API secret
--binance-environment [demo|real]
The environment to run in, demo for testnet, real for the production environment
--ftx-api-key TEXT Your FTX API key
--ftx-api-secret TEXT Your FTX API secret
--ftx-account-tier TEXT Your FTX Account Tier
--ftx-exchange-name TEXT Your FTX Exchange [FTX|FTX.US]
--kraken-api-key TEXT Your Kraken API key
--kraken-api-secret TEXT Your Kraken API secret
--kraken-verification-tier TEXT
Your Kraken Verification Tier
--node TEXT The name or id of the live node to run on
--auto-restart BOOLEAN Whether automatic algorithm restarting must be enabled
--notify-order-events BOOLEAN Whether notifications must be sent for order events
Expand Down Expand Up @@ -832,6 +840,7 @@ Options:
--ftx-api-key TEXT Your FTX API key
--ftx-api-secret TEXT Your FTX API secret
--ftx-account-tier TEXT Your FTX Account Tier
--ftx-exchange-name TEXT Your FTX Exchange [FTX|FTX.US]
--release Compile C# projects in release configuration instead of debug
--image TEXT The LEAN engine image to use (defaults to quantconnect/lean:latest)
--update Pull the LEAN engine image before starting live trading
Expand Down
4 changes: 2 additions & 2 deletions announcements.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"announcements": [
{
"date": "2022-01-25",
"message": "We've added support for Samco brokerage for India Market"
"date": "2022-01-26",
"message": "We've added support for Samco brokerage for India Market and FTX.US Exchange"
},
{
"date": "2021-11-17",
Expand Down
14 changes: 10 additions & 4 deletions lean/commands/live.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,9 @@ def _get_default_value(key: str) -> Optional[Any]:
type=str,
default=lambda: _get_default_value("ftx-account-tier"),
help="Your FTX Account Tier")
@click.option("--ftx-exchange-name",
type=str,
help="FTX exchange name [FTX, FTXUS]")
@click.option("--release",
is_flag=True,
default=False,
Expand Down Expand Up @@ -690,6 +693,7 @@ def live(project: Path,
ftx_api_key: Optional[str],
ftx_api_secret: Optional[str],
ftx_account_tier: Optional[str],
ftx_exchange_name: Optional[str],
release: bool,
image: Optional[str],
update: bool) -> None:
Expand Down Expand Up @@ -865,11 +869,12 @@ def live(project: Path,
kraken_api_secret,
kraken_verification_tier)
elif brokerage == FTXBrokerage.get_name():
ensure_options(["ftx_api_key", "ftx_api_secret", "ftx_account_tier"])
ensure_options(["ftx_api_key", "ftx_api_secret", "ftx_account_tier", "ftx_exchange_name"])
brokerage_configurer = FTXBrokerage(_get_organization_id(ftx_organization, "FTX"),
ftx_api_key,
ftx_api_secret,
ftx_account_tier)
ftx_account_tier,
ftx_exchange_name)

if data_feed == InteractiveBrokersDataFeed.get_name():
ensure_options(["ib_user_name", "ib_account", "ib_password", "ib_enable_delayed_streaming_data"])
Expand Down Expand Up @@ -995,12 +1000,13 @@ def live(project: Path,
kraken_api_secret,
kraken_verification_tier))
elif data_feed == FTXDataFeed.get_name():
ensure_options(["ftx_api_key", "ftx_api_secret", "ftx_account_tier"])
ensure_options(["ftx_api_key", "ftx_api_secret", "ftx_account_tier", "ftx_echange_name"])
data_feed_configurer = FTXDataFeed(
FTXBrokerage(_get_organization_id(ftx_organization, "FTX"),
ftx_api_key,
ftx_api_secret,
ftx_account_tier))
ftx_account_tier,
ftx_exchange_name))

environment_name = "lean-cli"
lean_config = lean_config_manager.get_complete_lean_config(environment_name, algorithm_file, None)
Expand Down
30 changes: 25 additions & 5 deletions lean/models/brokerages/cloud/ftx.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
class FTXBrokerage(CloudBrokerage):
"""A CloudBrokerage implementation for FTX."""

def __init__(self, api_key: str, secret_key: str, account_tier: str) -> None:
def __init__(self, api_key: str, secret_key: str, account_tier: str, exchange_name: str) -> None:
self._api_key = api_key
self._secret_key = secret_key
self._account_tier = account_tier
self._exchange_name = exchange_name

@classmethod
def get_id(cls) -> str:
Expand All @@ -37,19 +38,38 @@ def get_name(cls) -> str:

@classmethod
def build(cls, logger: Logger) -> CloudBrokerage:
exchange_name = click.prompt("FTX Exchange [FTX|FTXUS]")
exchange = FTXExchange() if exchange_name.casefold() == "FTX".casefold() else FTXUSExchange()

logger.info("""
Create an API key by logging in and accessing the FTX Profile page (https://ftx.com/profile).
""".strip())
Create an API key by logging in and accessing the {} Profile page (https://{}/profile).
""".format(exchange.get_name(), exchange.get_domain()).strip())

api_key = click.prompt("API key")
secret_key = logger.prompt_password("Secret key")
account_tier = click.prompt("Account Tier")

return FTXBrokerage(api_key, secret_key, account_tier)
return FTXBrokerage(api_key, secret_key, account_tier, exchange_name)

def _get_settings(self) -> Dict[str, str]:
return {
"key": self._api_key,
"secret": self._secret_key,
"accountTier": self._account_tier
"tier": self._account_tier,
"exchange": self._exchange_name,
"environment": "live"
}

class FTXExchange:
def get_name(self) -> str:
return "FTX"

def get_domain(self) -> str:
return "ftx.com"

class FTXUSExchange(FTXExchange):
def get_name(self) -> str:
return "FTXUS"

def get_domain(self) -> str:
return "ftx.us"
3 changes: 2 additions & 1 deletion lean/models/brokerages/cloud/kraken.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ def _get_settings(self) -> Dict[str, str]:
return {
"key": self._api_key,
"secret": self._secret_key,
"verificationTier": self._verification_tier
"verificationTier": self._verification_tier,
"environment": "live"
}
114 changes: 86 additions & 28 deletions lean/models/brokerages/local/ftx.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Any, Dict
from typing import Any, Dict, List

import click

Expand All @@ -22,17 +22,79 @@
from lean.models.config import LeanConfigConfigurer
from lean.models.logger import Option

class FTXExchange:
def get_name(self) -> str:
return "FTX"

def live_mode_brokerage(self) -> str:
return "FTXBrokerage"

def data_queue_handler_name(self) -> str:
return "FTXBrokerage"

def get_domain(self) -> str:
return "ftx.com"

def prefix(self) -> str:
return "ftx"

def account_tier_options(self) -> List[Option]:
return [Option(id="Tier1", label="Tier1"),
Option(id="Tier2", label="Tier2"),
Option(id="Tier3", label="Tier3"),
Option(id="Tier4", label="Tier4"),
Option(id="Tier5", label="Tier5"),
Option(id="Tier6", label="Tier6"),
Option(id="VIP1", label="VIP1"),
Option(id="VIP2", label="VIP2"),
Option(id="VIP3", label="VIP3"),
Option(id="MM1", label="MM1"),
Option(id="MM2", label="MM2"),
Option(id="MM3", label="MM3")]

class FTXUSExchange(FTXExchange):
def get_name(self) -> str:
return "FTXUS"

def live_mode_brokerage(self) -> str:
return "FTXUSBrokerage"

def data_queue_handler_name(self) -> str:
return "FTXUSBrokerage"

def get_domain(self) -> str:
return "ftx.us"

def prefix(self) -> str:
return "ftxus"

def account_tier_options(self) -> List[Option]:
return [Option(id="Tier1", label="Tier1"),
Option(id="Tier2", label="Tier2"),
Option(id="Tier3", label="Tier3"),
Option(id="Tier4", label="Tier4"),
Option(id="Tier5", label="Tier5"),
Option(id="Tier6", label="Tier6"),
Option(id="Tier7", label="Tier7"),
Option(id="Tier8", label="Tier8"),
Option(id="Tier9", label="Tier9"),
Option(id="VIP1", label="VIP1"),
Option(id="VIP2", label="VIP2"),
Option(id="MM1", label="MM1"),
Option(id="MM2", label="MM2"),
Option(id="MM3", label="MM3")]

class FTXBrokerage(LocalBrokerage):
"""A LocalBrokerage implementation for the FTX brokerage."""

_exchange: FTXExchange
_is_module_installed = False

def __init__(self, organization_id: str, api_key: str, api_secret: str, account_tier: str) -> None:
def __init__(self, organization_id: str, api_key: str, api_secret: str, account_tier: str, exchange: FTXExchange) -> None:
self._api_key = api_key
self._api_secret = api_secret
self._account_tier = account_tier
self._organization_id = organization_id
self._exchange = exchange

@classmethod
def get_name(cls) -> str:
Expand All @@ -46,50 +108,45 @@ def _build(cls, lean_config: Dict[str, Any], logger: Logger) -> LocalBrokerage:
options = [Option(id=organization.id, label=organization.name) for organization in organizations]

organization_id = logger.prompt_list(
"Select the organization with the FTX module subscription",
"Select the organization with the {} module subscription".format(cls.get_name()),
options
)

exchange_name = click.prompt("FTX Exchange [FTX|FTXUS]", cls._get_default(lean_config, "ftx-exchange-name"))
exchange = FTXExchange() if exchange_name.casefold() == "FTX".casefold() else FTXUSExchange()

logger.info("""
Create an API key by logging in and accessing the FTX Profile page (https://ftx.com/profile).
""".strip())
Create an API key by logging in and accessing the {} Profile page (https://{}/profile).
""".format(exchange.get_name(), exchange.get_domain()).strip())

api_key = click.prompt("API key", cls._get_default(lean_config, "ftx-api-key"))
api_secret = logger.prompt_password("API secret", cls._get_default(lean_config, "ftx-api-secret"))
prefix = exchange.prefix()
api_key = click.prompt("API key", cls._get_default(lean_config, f'{prefix}-api-key'))
api_secret = logger.prompt_password("API secret", cls._get_default(lean_config, f'{prefix}-api-secret'))

account_tier = logger.prompt_list(
"Select the Account Tier",
[Option(id="Tier1", label="Tier1"),
Option(id="Tier2", label="Tier2"),
Option(id="Tier3", label="Tier3"),
Option(id="Tier4", label="Tier4"),
Option(id="Tier5", label="Tier5"),
Option(id="Tier6", label="Tier6"),
Option(id="VIP1", label="VIP1"),
Option(id="VIP2", label="VIP2"),
Option(id="VIP3", label="VIP3"),
Option(id="MM1", label="MM1"),
Option(id="MM2", label="MM2"),
Option(id="MM3", label="MM3")],
cls._get_default(lean_config, "ftx-account-tier")
exchange.account_tier_options(),
cls._get_default(lean_config, f'{prefix}-account-tier')
)

return FTXBrokerage(organization_id, api_key, api_secret, account_tier)
return FTXBrokerage(organization_id, api_key, api_secret, account_tier, exchange)

def _configure_environment(self, lean_config: Dict[str, Any], environment_name: str) -> None:
self.ensure_module_installed()

lean_config["environments"][environment_name]["live-mode-brokerage"] = "FTXBrokerage"
lean_config["environments"][environment_name]["live-mode-brokerage"] = self._exchange.live_mode_brokerage()
lean_config["environments"][environment_name]["transaction-handler"] = \
"QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler"

def configure_credentials(self, lean_config: Dict[str, Any]) -> None:
lean_config["ftx-api-key"] = self._api_key
lean_config["ftx-api-secret"] = self._api_secret
lean_config["ftx-account-tier"] = self._account_tier
prefix = self._exchange.prefix()

lean_config[f'{prefix}-api-key'] = self._api_key
lean_config[f'{prefix}-api-secret'] = self._api_secret
lean_config[f'{prefix}-account-tier'] = self._account_tier
lean_config["job-organization-id"] = self._organization_id

self._save_properties(lean_config, ["job-organization-id", "ftx-api-key", "ftx-api-secret", "ftx-account-tier"])
self._save_properties(lean_config, ["job-organization-id", f'{prefix}-api-key', f'{prefix}-api-secret', f'{prefix}-account-tier'])

def ensure_module_installed(self) -> None:
if not self._is_module_installed:
Expand All @@ -98,6 +155,7 @@ def ensure_module_installed(self) -> None:

class FTXDataFeed(LeanConfigConfigurer):
"""A LeanConfigConfigurer implementation for the FTX data feed."""
_brokerage: Any

def __init__(self, brokerage: FTXBrokerage) -> None:
self._brokerage = brokerage
Expand All @@ -113,7 +171,7 @@ def build(cls, lean_config: Dict[str, Any], logger: Logger) -> LeanConfigConfigu
def configure(self, lean_config: Dict[str, Any], environment_name: str) -> None:
self._brokerage.ensure_module_installed()

lean_config["environments"][environment_name]["data-queue-handler"] = "FTXBrokerage"
lean_config["environments"][environment_name]["data-queue-handler"] = self._brokerage._exchange.data_queue_handler_name()
lean_config["environments"][environment_name]["history-provider"] = "BrokerageHistoryProvider"

self._brokerage.configure_credentials(lean_config)

0 comments on commit 0e989b3

Please sign in to comment.