Skip to content

Commit

Permalink
add is_tradable check
Browse files Browse the repository at this point in the history
  • Loading branch information
NelsonDane committed Aug 2, 2024
1 parent c881c85 commit e7e22b7
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Do not use any version of this library before 1.0.9. Earlier versions had a bug
## Installation

```bash
pip install 'fennel-invest-api>=1.0.9'
pip install 'fennel-invest-api>=1.1.0'
```

## Usage: Logging In
Expand Down
51 changes: 15 additions & 36 deletions fennel_invest_api/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,42 +36,6 @@ def account_ids_query(self):
"""
return json.dumps(self.build_graphql_payload(query))

# This returns 503 for some users,
# so best to run account_ids_query and then portfolio_query
# def list_full_accounts_query(self):
# query = """
# query ListFullAccounts {
# user {
# id
# accounts {
# name
# id
# created
# isPrimary
# status
# portfolio {
# id
# totalEquityValue
# cash {
# balance {
# canTrade
# canWithdraw
# reservedBalance
# settledBalance
# tradeBalance
# tradeDecrease
# tradeIncrease
# }
# currency
# }
# totalEquityValue
# }
# }
# }
# }
# """
# return json.dumps(self.build_graphql_payload(query))

def portfolio_query(self, account_id):
query = """
query GetPortfolioSummary($accountId: String!) {
Expand Down Expand Up @@ -133,6 +97,21 @@ def is_market_open_query(self):
"""
return json.dumps(self.build_graphql_payload(query))

def is_tradable_query(self, isin, account_id):
query = """
query GetTradeable($isin: String!, $accountId: String) {
bulbBulb(isin: $isin) {
tradeable(accountId: $accountId) {
canBuy
canSell
restrictionReason
}
}
}
"""
variables = {"isin": isin, "accountId": account_id}
return json.dumps(self.build_graphql_payload(query, variables))

def stock_search_query(self, symbol, count=5):
# idk what count is
query = """
Expand Down
23 changes: 23 additions & 0 deletions fennel_invest_api/fennel.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,25 @@ def get_stock_isin(self, ticker):
quote = self.get_stock_quote(ticker)
return None if quote is None else quote["isin"]

@check_login
def is_stock_tradable(self, isin, account_id, side="buy"):
query = self.endpoints.is_tradable_query(isin, account_id)
headers = self.endpoints.build_headers(self.Bearer)
response = self.session.post(
self.endpoints.graphql, headers=headers, data=query
)
if response.status_code != 200:
raise Exception(
f"Tradable Request failed with status code {response.status_code}: {response.text}"
)
response = response.json()
can_trade = response["data"]["bulbBulb"]["tradeable"]
if can_trade is None:
return False, "No tradeable data found"
if side.lower() == "buy":
return can_trade["canBuy"], can_trade["restrictionReason"]
return can_trade["canSell"], can_trade["restrictionReason"]

@check_login
def place_order(
self, account_id, ticker, quantity, side, price="market", dry_run=False
Expand All @@ -281,6 +300,10 @@ def place_order(
isin = self.get_stock_isin(ticker)
if isin is None:
raise Exception(f"Failed to find ISIN for stock with ticker {ticker}")
# Check if stock is tradable
can_trade, restriction_reason = self.is_stock_tradable(isin, account_id, side)
if not can_trade:
raise Exception(f"Stock {ticker} is not tradable: {restriction_reason}")
if dry_run:
return {
"account_id": account_id,
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="fennel_invest_api",
version="1.0.9.2",
version="1.1.0",
description="Unofficial Fennel.com Invest API written in Python Requests",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
Expand Down

0 comments on commit e7e22b7

Please sign in to comment.