Skip to content

Commit

Permalink
Merge pull request #62 from rjra2611/feature-add-support-for-samco
Browse files Browse the repository at this point in the history
Add Samco brokearge (India)
  • Loading branch information
Martin-Molinero authored Jan 25, 2022
2 parents b8c8803 + 42cdc4a commit 3574479
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 2 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -720,9 +720,9 @@ Options:
-d, --detach Run the live deployment in a detached Docker container and return immediately
--gui Enable monitoring and controlling of the deployment via the local GUI
--gui-organization TEXT The name or id of the organization with the local GUI module subscription
--brokerage [Paper Trading|Interactive Brokers|Tradier|OANDA|Bitfinex|Coinbase Pro|Binance|Zerodha|Terminal Link|Atreyu|Trading Technologies|Kraken|FTX]
--brokerage [Paper Trading|Interactive Brokers|Tradier|OANDA|Bitfinex|Coinbase Pro|Binance|Zerodha|Samco|Terminal Link|Atreyu|Trading Technologies|Kraken|FTX]
The brokerage to use
--data-feed [Interactive Brokers|Tradier|OANDA|Bitfinex|Coinbase Pro|Binance|Zerodha|Terminal Link|Trading Technologies|Custom data only|Kraken|FTX|IQFeed]
--data-feed [Interactive Brokers|Tradier|OANDA|Bitfinex|Coinbase Pro|Binance|Zerodha|Samco|Terminal Link|Trading Technologies|Custom data only|Kraken|FTX|IQFeed]
The data feed to use
--ib-user-name TEXT Your Interactive Brokers username
--ib-account TEXT Your Interactive Brokers account id
Expand Down Expand Up @@ -759,6 +759,18 @@ Options:
--zerodha-history-subscription BOOLEAN
Whether you have a history API subscription for Zerodha
--samco-organization TEXT The name or id of the organization with the samco module subscription
--samco-client-id TEXT Your Samco account Client ID
--samco-client-password TEXT Your Samco account password
--samco-year-of-birth TEXT Your year of birth (YYYY) registered with Samco
--samco-product-type [MIS|CNC|NRML]
MIS if you are targeting intraday products, CNC if you are targeting delivery
products, NRML if you are targeting carry forward products
--samco-trading-segment [EQUITY|COMMODITY]
EQUITY if you are trading equities on NSE or BSE, COMMODITY if you are trading
commodities on MCX
--iqfeed-iqconnect FILE The path to the IQConnect binary
--iqfeed-username TEXT Your IQFeed username
--iqfeed-password TEXT Your IQFeed password
Expand Down
4 changes: 4 additions & 0 deletions announcements.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"announcements": [
{
"date": "2022-01-25",
"message": "We've added support for Samco brokerage for India Market"
},
{
"date": "2021-11-17",
"message": "We've added support for Kraken and FTX brokerages"
Expand Down
57 changes: 57 additions & 0 deletions lean/commands/live.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from lean.models.brokerages.local.tradier import TradierBrokerage, TradierDataFeed
from lean.models.brokerages.local.trading_technologies import TradingTechnologiesBrokerage, TradingTechnologiesDataFeed
from lean.models.brokerages.local.zerodha import ZerodhaBrokerage, ZerodhaDataFeed
from lean.models.brokerages.local.samco import SamcoBrokerage, SamcoDataFeed
from lean.models.brokerages.local.kraken import KrakenBrokerage, KrakenDataFeed
from lean.models.brokerages.local.ftx import FTXBrokerage, FTXDataFeed
from lean.models.errors import MoreInfoError
Expand All @@ -50,6 +51,7 @@
"BitfinexBrokerage": ["bitfinex-api-secret", "bitfinex-api-key"],
"BinanceBrokerage": ["binance-api-secret", "binance-api-key"],
"ZerodhaBrokerage": ["zerodha-access-token", "zerodha-api-key", "zerodha-product-type", "zerodha-trading-segment"],
"SamcoBrokerage": ["samco-client-id", "samco-client-password", "samco-year-of-birth", "samco-product-type", "samco-trading-segment"],
"BloombergBrokerage": ["job-organization-id", "bloomberg-api-type", "bloomberg-environment",
"bloomberg-server-host", "bloomberg-server-port", "bloomberg-emsx-broker"],
"AtreyuBrokerage": ["job-organization-id", "atreyu-host", "atreyu-req-port", "atreyu-sub-port",
Expand All @@ -76,6 +78,7 @@
"BitfinexBrokerage": _required_brokerage_properties["BitfinexBrokerage"],
"BinanceBrokerage": _required_brokerage_properties["BinanceBrokerage"],
"ZerodhaBrokerage": _required_brokerage_properties["ZerodhaBrokerage"] + ["zerodha-history-subscription"],
"SamcoBrokerage": _required_brokerage_properties["SamcoBrokerage"],
"BloombergBrokerage": _required_brokerage_properties["BloombergBrokerage"],
"TradingTechnologiesBrokerage": _required_brokerage_properties["TradingTechnologiesBrokerage"],
"QuantConnect.ToolBox.IQFeed.IQFeedDataQueueHandler": ["iqfeed-iqconnect", "iqfeed-productName", "iqfeed-version"],
Expand Down Expand Up @@ -364,6 +367,30 @@ def _get_default_value(key: str) -> Optional[Any]:
type=bool,
default=lambda: _get_default_value("zerodha-history-subscription"),
help="Whether you have a history API subscription for Zerodha")
@click.option("--samco-organization",
type=str,
default=lambda: _get_default_value("job-organization-id"),
help="The name or id of the organization with the samco module subscription")
@click.option("--samco-client-id",
type=str,
default=lambda: _get_default_value("samco-client-id"),
help="Your Samco account Client ID")
@click.option("--samco-client-password",
type=str,
default=lambda: _get_default_value("samco-client-password"),
help="Your Samco account password")
@click.option("--samco-year-of-birth",
type=str,
default=lambda: _get_default_value("samco-year-of-birth"),
help="Your year of birth (YYYY) registered with Samco")
@click.option("--samco-product-type",
type=click.Choice(["MIS", "CNC", "NRML"], case_sensitive=False),
default=lambda: _get_default_value("samco-product-type"),
help="MIS if you are targeting intraday products, CNC if you are targeting delivery products, NRML if you are targeting carry forward products")
@click.option("--samco-trading-segment",
type=click.Choice(["EQUITY", "COMMODITY"], case_sensitive=False),
default=lambda: _get_default_value("samco-trading-segment"),
help="EQUITY if you are trading equities on NSE or BSE, COMMODITY if you are trading commodities on MCX")
@click.option("--iqfeed-iqconnect",
type=PathParameter(exists=True, file_okay=True, dir_okay=False),
default=lambda: _get_default_value("iqfeed-iqconnect"),
Expand Down Expand Up @@ -607,6 +634,12 @@ def live(project: Path,
zerodha_product_type: Optional[str],
zerodha_trading_segment: Optional[str],
zerodha_history_subscription: Optional[bool],
samco_organization: Optional[str],
samco_client_id: Optional[str],
samco_client_password: Optional[str],
samco_year_of_birth: Optional[str],
samco_product_type: Optional[str],
samco_trading_segment: Optional[str],
iqfeed_iqconnect: Optional[Path],
iqfeed_username: Optional[str],
iqfeed_password: Optional[str],
Expand Down Expand Up @@ -744,6 +777,18 @@ def live(project: Path,
zerodha_access_token,
zerodha_product_type,
zerodha_trading_segment)
elif brokerage == SamcoBrokerage.get_name():
ensure_options(["samco_client_id",
"samco_client_password",
"samco_year_of_birth",
"samco_product_type",
"samco_trading_segment"])
brokerage_configurer = SamcoBrokerage(_get_organization_id(samco_organization, "Samco"),
samco_client_id,
samco_client_password,
samco_year_of_birth,
samco_product_type,
samco_trading_segment)
elif brokerage == TerminalLinkBrokerage.get_name():
ensure_options(["bloomberg_environment",
"bloomberg_server_host",
Expand Down Expand Up @@ -867,6 +912,18 @@ def live(project: Path,
zerodha_product_type,
zerodha_trading_segment),
zerodha_history_subscription)
elif data_feed == SamcoDataFeed.get_name():
ensure_options(["samco_client_id",
"samco_client_password",
"samco_year_of_birth",
"samco_product_type",
"samco_trading_segment"])
data_feed_configurer = SamcoDataFeed(SamcoBrokerage(_get_organization_id(samco_organization, "Samco"),
samco_client_id,
samco_client_password,
samco_year_of_birth,
samco_product_type,
samco_trading_segment))
elif data_feed == TerminalLinkDataFeed.get_name():
ensure_options(["bloomberg_environment",
"bloomberg_server_host",
Expand Down
3 changes: 3 additions & 0 deletions lean/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
# The product id of the FTX module
FTX_PRODUCT_ID = 138

# The product id of the SAMCO module
SAMCO_PRODUCT_ID = 173

# The product ids for which a valid subscription is seen as a valid GUI module subscription
GUI_PRODUCT_SUBSCRIPTION_IDS = [119, 120]

Expand Down
4 changes: 4 additions & 0 deletions lean/models/brokerages/local/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from lean.models.brokerages.local.tradier import TradierBrokerage, TradierDataFeed
from lean.models.brokerages.local.trading_technologies import TradingTechnologiesBrokerage, TradingTechnologiesDataFeed
from lean.models.brokerages.local.zerodha import ZerodhaBrokerage, ZerodhaDataFeed
from lean.models.brokerages.local.samco import SamcoBrokerage, SamcoDataFeed
from lean.models.brokerages.local.kraken import KrakenBrokerage, KrakenDataFeed
from lean.models.brokerages.local.ftx import FTXBrokerage, FTXDataFeed
from lean.models.config import LeanConfigConfigurer
Expand All @@ -42,6 +43,7 @@
CoinbaseProBrokerage,
BinanceBrokerage,
ZerodhaBrokerage,
SamcoBrokerage,
TerminalLinkBrokerage,
AtreyuBrokerage,
TradingTechnologiesBrokerage,
Expand All @@ -57,6 +59,7 @@
CoinbaseProDataFeed,
BinanceDataFeed,
ZerodhaDataFeed,
SamcoDataFeed,
TerminalLinkDataFeed,
TradingTechnologiesDataFeed,
CustomDataOnlyDataFeed,
Expand All @@ -73,6 +76,7 @@
CoinbaseProBrokerage: [CoinbaseProDataFeed],
BinanceBrokerage: [BinanceDataFeed],
ZerodhaBrokerage: [ZerodhaDataFeed],
SamcoBrokerage: [SamcoDataFeed],
TerminalLinkBrokerage: [TerminalLinkDataFeed],
AtreyuBrokerage: [x for x in all_local_data_feeds if x != CustomDataOnlyDataFeed],
TradingTechnologiesBrokerage: [TradingTechnologiesDataFeed],
Expand Down
133 changes: 133 additions & 0 deletions lean/models/brokerages/local/samco.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# 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.

from typing import Any, Dict

import click

from lean.components.util.logger import Logger
from lean.container import container
from lean.constants import SAMCO_PRODUCT_ID
from lean.models.brokerages.local.base import LocalBrokerage
from lean.models.config import LeanConfigConfigurer
from lean.models.logger import Option

class SamcoBrokerage(LocalBrokerage):
"""A LocalBrokerage implementation for the Samco brokerage."""

_is_module_installed = False

def __init__(self, organization_id: str, client_id: str, client_password: str, year_of_birth: str, product_type: str, trading_segment: str) -> None:
self._organization_id = organization_id
self._client_id = client_id
self._client_password = client_password
self._year_of_birth = year_of_birth
self._product_type = product_type
self._trading_segment = trading_segment

@classmethod
def get_name(cls) -> str:
return "Samco"

@classmethod
def get_module_id(cls) -> int:
return SAMCO_PRODUCT_ID

@classmethod
def _build(cls, lean_config: Dict[str, Any], logger: Logger) -> LocalBrokerage:

api_client = container.api_client()

organizations = api_client.organizations.get_all()
options = [Option(id=organization.id, label=organization.name) for organization in organizations]

organization_id = logger.prompt_list(
"Select the organization with the Samco module subscription",
options
)

client_id = click.prompt("Client ID", cls._get_default(lean_config, "samco-client-id"))
client_password = logger.prompt_password("Client Password", cls._get_default(lean_config, "samco-client-password"))
year_of_birth = click.prompt("Year of Birth", cls._get_default(lean_config, "samco-year-of-birth"))

logger.info("""
The product type must be set to MIS if you are targeting intraday products, CNC if you are targeting delivery products or NRML if you are targeting carry forward products.
""".strip())

product_type = click.prompt(
"Product type",
cls._get_default(lean_config, "samco-product-type"),
type=click.Choice(["MIS", "CNC", "NRML"], case_sensitive=False)
)

logger.info("""
The trading segment must be set to EQUITY if you are trading equities on NSE or BSE, or COMMODITY if you are trading commodities on MCX.
""".strip())

trading_segment = click.prompt(
"Trading segment",
cls._get_default(lean_config, "samco-trading-segment"),
type=click.Choice(["EQUITY", "COMMODITY"], case_sensitive=False)
)

return SamcoBrokerage(organization_id, client_id, client_password, year_of_birth, product_type, trading_segment)

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"] = "SamcoBrokerage"
lean_config["environments"][environment_name]["transaction-handler"] = \
"QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler"

def configure_credentials(self, lean_config: Dict[str, Any]) -> None:
lean_config["job-organization-id"] = self._organization_id
lean_config["samco-client-id"] = self._client_id
lean_config["samco-client-password"] = self._client_password
lean_config["samco-year-of-birth"] = self._year_of_birth
lean_config["samco-product-type"] = self._product_type
lean_config["samco-trading-segment"] = self._trading_segment

self._save_properties(lean_config, ["job-organization-id",
"samco-client-id",
"samco-client-password",
"samco-year-of-birth",
"samco-product-type",
"samco-trading-segment"])

def ensure_module_installed(self) -> None:
if not self._is_module_installed:
container.module_manager().install_module(self.__class__.get_module_id(), self._organization_id)
self._is_module_installed = True

class SamcoDataFeed(LeanConfigConfigurer):
"""A LeanConfigConfigurer implementation for the Samco data feed."""

def __init__(self, brokerage: SamcoBrokerage) -> None:
self._brokerage = brokerage

@classmethod
def get_name(cls) -> str:
return SamcoBrokerage.get_name()

@classmethod
def build(cls, lean_config: Dict[str, Any], logger: Logger) -> LeanConfigConfigurer:
brokerage = SamcoBrokerage.build(lean_config, logger)

return SamcoDataFeed(brokerage)

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"] = "SamcoBrokerage"
lean_config["environments"][environment_name]["history-provider"] = "BrokerageHistoryProvider"

self._brokerage.configure_credentials(lean_config)

0 comments on commit 3574479

Please sign in to comment.