Skip to content

Commit

Permalink
Merge pull request #325 from Lumiwealth/tradier_initial_creation
Browse files Browse the repository at this point in the history
tradier: new broker and data_source skeleton code added along with in…
  • Loading branch information
grzesir authored Nov 28, 2023
2 parents e11cbae + 5fa1389 commit 1d7d0b1
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 0 deletions.
1 change: 1 addition & 0 deletions lumibot/brokers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .broker import Broker
from .ccxt import Ccxt
from .interactive_brokers import InteractiveBrokers
from .tradier import Tradier
69 changes: 69 additions & 0 deletions lumibot/brokers/tradier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from lumibot.brokers import Broker
from lumibot.data_sources import TRADIER_LIVE_API_URL, TRADIER_PAPER_API_URL, TradierAPIError, TradierData
from lumibot.entities import Asset, Order


class Tradier(Broker):
"""
Broker that connects to Tradier API to place orders and retrieve data
"""
def __init__(self, account_id=None, api_token=None, paper=True, config=None, max_workers=20, connect_stream=True,
data_source=None):

if data_source is None:
data_source = TradierData(account_id=account_id, api_key=api_token, paper=paper, max_workers=max_workers)

super().__init__(name='Tradier', data_source=data_source, config=config, max_workers=max_workers,
connect_stream=connect_stream)

self._tradier_api_key = api_token
self._tradier_account_id = account_id
self._tradier_paper = paper
self._tradier_base_url = TRADIER_PAPER_API_URL if self._tradier_paper else TRADIER_LIVE_API_URL

try:
self.validate_credentials()
except TradierAPIError as e:
raise TradierAPIError("Invalid Tradier Credentials") from e

def validate_credentials(self):
pass

def cancel_order(self, order: Order):
pass

def _submit_order(self, order: Order):
pass

def _get_balances_at_broker(self, quote_asset: Asset) -> float:
pass

def get_historical_account_value(self):
pass

def _get_stream_object(self):
pass

def _register_stream_events(self):
pass

def _run_stream(self):
pass

def _parse_broker_position(self, broker_position, strategy, orders=None):
pass

def _pull_broker_position(self, asset: Asset):
pass

def _pull_broker_positions(self, strategy=None):
pass

def _parse_broker_order(self, response, strategy_name, strategy_object=None):
pass

def _pull_broker_order(self, identifier):
pass

def _pull_broker_open_orders(self):
pass
7 changes: 7 additions & 0 deletions lumibot/data_sources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@
from .exceptions import NoDataFound, UnavailabeTimestep
from .interactive_brokers_data import InteractiveBrokersData
from .pandas_data import PandasData
from .tradier_data import (
TRADIER_LIVE_API_URL,
TRADIER_PAPER_API_URL,
TRADIER_STREAM_API_URL,
TradierAPIError,
TradierData,
)
from .tradovate_data import TradovateData
from .yahoo_data import YahooData
35 changes: 35 additions & 0 deletions lumibot/data_sources/tradier_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from .data_source import DataSource

TRADIER_LIVE_API_URL = "https://api.tradier.com/v1/"
TRADIER_PAPER_API_URL = "https://sandbox.tradier.com/v1/"
TRADIER_STREAM_API_URL = "https://stream.tradier.com/v1/" # Only valid Live, no Paper support


class TradierAPIError(Exception):
pass


class TradierData(DataSource):
MIN_TIMESTEP = "minute"
SOURCE = "Tradier"

def __init__(self, account_id, api_key, paper=True, max_workers=20):
super().__init__(api_key=api_key)
self._account_id = account_id
self._paper = paper
self._base_url = TRADIER_PAPER_API_URL if self._paper else TRADIER_LIVE_API_URL
self.max_workers = min(max_workers, 50)

def _pull_source_symbol_bars(self, asset, length, timestep=MIN_TIMESTEP, timeshift=None, quote=None, exchange=None,
include_after_hours=True):
pass

def _pull_source_bars(self, assets, length, timestep=MIN_TIMESTEP, timeshift=None, quote=None,
include_after_hours=True):
pass

def _parse_source_symbol_bars(self, response, asset, quote=None, length=None):
pass

def get_last_price(self, asset, quote=None, exchange=None):
pass
15 changes: 15 additions & 0 deletions tests/test_tradier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from lumibot.brokers import Tradier
from lumibot.data_sources import TradierData


class TestTradierData:
def test_basics(self):
tdata = TradierData(account_id="1234", api_key="a1b2c3", paper=True)
assert tdata._account_id == "1234"


class TestTradierBroker:
def test_basics(self):
broker = Tradier(account_id="1234", api_token="a1b2c3", paper=True)
assert broker.name == "Tradier"
assert broker._tradier_account_id == "1234"

0 comments on commit 1d7d0b1

Please sign in to comment.