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

tradier: new broker and data_source skeleton code added along with in… #325

Merged
merged 1 commit into from
Nov 28, 2023

Conversation

davidlatte
Copy link
Collaborator

…itial unit tests.

Copy link
Contributor

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Korbit AI Mentor has reviewed your code. To discuss an issue, reply using the tag @korbit-ai-mentor.


Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

Comment on lines +29 to +30
def validate_credentials(self):
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 9

The validate_credentials method is currently empty. It's important to implement this method to ensure that the provided API token and account ID are valid before making any API calls.

Suggested change
def validate_credentials(self):
pass
def validate_credentials(self):
response = requests.get(self._tradier_base_url + '/v1/user/profile', headers={'Authorization': 'Bearer ' + self._tradier_api_key})
if response.status_code != 200:
raise TradierAPIError('Invalid Tradier Credentials')

Comment on lines +16 to +17
def __init__(self, account_id, api_key, paper=True, max_workers=20):
super().__init__(api_key=api_key)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 9

The class 'TradierData' inherits from 'DataSource' but does not call the parent constructor with all the necessary arguments. The parent constructor requires 'name' and 'config' arguments which are not provided in the child class constructor.

Suggested change
def __init__(self, account_id, api_key, paper=True, max_workers=20):
super().__init__(api_key=api_key)
def __init__(self, account_id, api_key, paper=True, max_workers=20):
name = 'TradierData'
config = {'account_id': account_id, 'api_key': api_key, 'paper': paper, 'max_workers': max_workers}
super().__init__(name=name, config=config)

Comment on lines +32 to +33
def cancel_order(self, order: Order):
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 8

The cancel_order method is currently empty. This method should be implemented to allow users to cancel orders.

Suggested change
def cancel_order(self, order: Order):
pass
def cancel_order(self, order: Order):
response = requests.delete(self._tradier_base_url + '/v1/accounts/' + self._tradier_account_id + '/orders/' + order.id, headers={'Authorization': 'Bearer ' + self._tradier_api_key})
if response.status_code != 200:
raise TradierAPIError('Failed to cancel order')

Comment on lines +35 to +36
def _submit_order(self, order: Order):
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 8

The _submit_order method is currently empty. This method should be implemented to allow users to submit orders.

Suggested change
def _submit_order(self, order: Order):
pass
def _submit_order(self, order: Order):
data = {'class': order.order_class, 'symbol': order.symbol, 'side': order.side, 'quantity': order.quantity, 'type': order.order_type}
response = requests.post(self._tradier_base_url + '/v1/accounts/' + self._tradier_account_id + '/orders', headers={'Authorization': 'Bearer ' + self._tradier_api_key}, data=data)
if response.status_code != 201:
raise TradierAPIError('Failed to submit order')

Comment on lines +38 to +39
def _get_balances_at_broker(self, quote_asset: Asset) -> float:
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 8

The _get_balances_at_broker method is currently empty. This method should be implemented to allow users to retrieve their account balance.

Suggested change
def _get_balances_at_broker(self, quote_asset: Asset) -> float:
pass
def _get_balances_at_broker(self, quote_asset: Asset) -> float:
response = requests.get(self._tradier_base_url + '/v1/accounts/' + self._tradier_account_id + '/balances', headers={'Authorization': 'Bearer ' + self._tradier_api_key})
if response.status_code != 200:
raise TradierAPIError('Failed to get account balance')
return float(response.json()['equity'])

Comment on lines +41 to +42
def get_historical_account_value(self):
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 8

The get_historical_account_value method is currently empty. This method should be implemented to allow users to retrieve their historical account value.

Suggested change
def get_historical_account_value(self):
pass
def get_historical_account_value(self):
response = requests.get(self._tradier_base_url + '/v1/accounts/' + self._tradier_account_id + '/history', headers={'Authorization': 'Bearer ' + self._tradier_api_key})
if response.status_code != 200:
raise TradierAPIError('Failed to get historical account value')
return response.json()['history']

Comment on lines +5 to +15
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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 7

The test cases in the test_tradier.py file are quite basic and do not cover all the methods in the Tradier broker and data source classes. It's important to have comprehensive tests to ensure all parts of the code are working as expected.

Comment on lines +5 to +15
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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Bug Risk priority 6

The test cases are not checking for any potential errors or exceptions. It's important to include negative test cases to ensure the code can handle errors gracefully.

"""
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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Code Design Improvements priority 6

The __init__ method is quite long and complex. It's a good practice to keep methods short and simple for better readability and maintainability. Consider breaking it down into smaller methods.

Comment on lines +8 to +15
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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Code Design Improvements priority 5

The test cases are directly accessing private variables of the classes. This is against our coding standards. Instead, use getter methods or properties to access these variables.

Comment on lines +9 to +15
from .tradier_data import (
TRADIER_LIVE_API_URL,
TRADIER_PAPER_API_URL,
TRADIER_STREAM_API_URL,
TradierAPIError,
TradierData,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Code Design Improvements priority 4

The import statements for the Tradier API URLs (TRADIER_LIVE_API_URL, TRADIER_PAPER_API_URL, TRADIER_STREAM_API_URL) might not be necessary in this file. If these constants are only used in the TradierData class, they should be imported there instead. This would keep the __init__.py file cleaner and more focused on its main purpose of making the necessary classes and functions available for import from the lumibot.data_sources package.

Suggested change
from .tradier_data import (
TRADIER_LIVE_API_URL,
TRADIER_PAPER_API_URL,
TRADIER_STREAM_API_URL,
TradierAPIError,
TradierData,
)
from .tradier_data import (
TradierAPIError,
TradierData
)

Comment on lines +9 to +15
from .tradier_data import (
TRADIER_LIVE_API_URL,
TRADIER_PAPER_API_URL,
TRADIER_STREAM_API_URL,
TradierAPIError,
TradierData,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Formatting Improvements priority 3

The import statements for the Tradier data source are not grouped together. According to PEP 8, related import statements should be grouped together and separated by a blank line from other import groups. This makes the code easier to read and understand.

Comment on lines +9 to +15
from .tradier_data import (
TRADIER_LIVE_API_URL,
TRADIER_PAPER_API_URL,
TRADIER_STREAM_API_URL,
TradierAPIError,
TradierData,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

category Formatting Improvements priority 2

The import statements are not in alphabetical order. According to our company's coding standards, import statements should be sorted alphabetically to make it easier to find specific imports when the list gets long.

@grzesir grzesir merged commit 1d7d0b1 into dev Nov 28, 2023
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants