Wrap API calls in helper and validate response
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
from pydantic import ValidationError
|
||||
|
||||
from core.util import logs
|
||||
|
||||
|
||||
@@ -8,11 +10,36 @@ class BaseExchange(object):
|
||||
self.log = logs.get_logger(name)
|
||||
self.client = None
|
||||
|
||||
self.set_schema()
|
||||
self.connect()
|
||||
|
||||
def set_schema(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def connect(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def call(self, method, *args, **kwargs) -> (bool, dict):
|
||||
|
||||
if hasattr(self.client, method):
|
||||
try:
|
||||
response = getattr(self.client, method)(*args, **kwargs)
|
||||
if isinstance(response, list):
|
||||
response = {"itemlist": response}
|
||||
if method not in self.schema:
|
||||
self.log.error(f"Method cannot be validated: {method}")
|
||||
self.log.debug(f"Response: {response}")
|
||||
return (False, f"Method cannot be validated: {method}")
|
||||
return (True, self.schema[method](**response).dict())
|
||||
except ValidationError as e:
|
||||
self.log.error(f"Could not validate response: {e}")
|
||||
return (False, e)
|
||||
except Exception as e:
|
||||
self.log.error(f"Error calling {method}: {e}")
|
||||
return (False, e)
|
||||
else:
|
||||
return (False, "No such method")
|
||||
|
||||
def get_account(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@@ -8,9 +8,20 @@ from alpaca.trading.requests import (
|
||||
)
|
||||
|
||||
from core.exchanges import BaseExchange
|
||||
from core.lib.schemas import alpaca_s
|
||||
|
||||
ALPACA_SCHEMA_MAPPING = {
|
||||
"get_account": alpaca_s.GetAccount,
|
||||
"get_all_assets": alpaca_s.GetAllAssets,
|
||||
"get_all_positions": alpaca_s.GetAllPositions,
|
||||
"get_open_position": alpaca_s.GetOpenPosition,
|
||||
}
|
||||
|
||||
|
||||
class AlpacaExchange(BaseExchange):
|
||||
def set_schema(self):
|
||||
self.schema = ALPACA_SCHEMA_MAPPING
|
||||
|
||||
def connect(self):
|
||||
self.client = TradingClient(
|
||||
self.account.api_key,
|
||||
@@ -20,32 +31,31 @@ class AlpacaExchange(BaseExchange):
|
||||
)
|
||||
|
||||
def get_account(self):
|
||||
return self.client.get_account()
|
||||
return self.call("get_account")
|
||||
|
||||
def get_supported_assets(self):
|
||||
try:
|
||||
request = GetAssetsRequest(status="active", asset_class="crypto")
|
||||
assets = self.client.get_all_assets(filter=request)
|
||||
asset_list = [x["symbol"] for x in assets if "symbol" in x]
|
||||
print("Supported symbols", asset_list)
|
||||
except APIError as e:
|
||||
self.log.error(f"Could not get asset list: {e}")
|
||||
# return False
|
||||
return asset_list
|
||||
request = GetAssetsRequest(status="active", asset_class="crypto")
|
||||
success, assets = self.call("get_all_assets", filter=request)
|
||||
# assets = self.client.get_all_assets(filter=request)
|
||||
if not success:
|
||||
return (success, assets)
|
||||
assets = assets["itemlist"]
|
||||
asset_list = [x["symbol"] for x in assets if "symbol" in x]
|
||||
print("Supported symbols", asset_list)
|
||||
|
||||
return (True, asset_list)
|
||||
|
||||
def get_balance(self):
|
||||
try:
|
||||
account_info = self.client.get_account()
|
||||
except APIError as e:
|
||||
self.log.error(f"Could not get account balance: {e}")
|
||||
return False
|
||||
success, account_info = self.call("get_account")
|
||||
if not success:
|
||||
return (success, account_info)
|
||||
equity = account_info["equity"]
|
||||
try:
|
||||
balance = float(equity)
|
||||
except ValueError:
|
||||
return False
|
||||
return (False, "Invalid balance")
|
||||
|
||||
return balance
|
||||
return (True, balance)
|
||||
|
||||
def get_market_value(self, symbol):
|
||||
try:
|
||||
@@ -89,6 +99,8 @@ class AlpacaExchange(BaseExchange):
|
||||
order = self.client.submit_order(order_data=market_order_data)
|
||||
except APIError as e:
|
||||
self.log.error(f"Error placing market order: {e}")
|
||||
trade.status = "error"
|
||||
trade.save()
|
||||
return (False, e)
|
||||
elif trade.type == "limit":
|
||||
if not trade.price:
|
||||
@@ -99,6 +111,8 @@ class AlpacaExchange(BaseExchange):
|
||||
order = self.client.submit_order(order_data=limit_order_data)
|
||||
except APIError as e:
|
||||
self.log.error(f"Error placing limit order: {e}")
|
||||
trade.status = "error"
|
||||
trade.save()
|
||||
return (False, e)
|
||||
|
||||
else:
|
||||
@@ -120,19 +134,19 @@ class AlpacaExchange(BaseExchange):
|
||||
pass
|
||||
|
||||
def get_position_info(self, asset_id):
|
||||
try:
|
||||
position = self.client.get_open_position(asset_id)
|
||||
except APIError as e:
|
||||
return (False, e)
|
||||
success, position = self.call("get_open_position", asset_id)
|
||||
if not success:
|
||||
return (success, position)
|
||||
return (True, position)
|
||||
|
||||
def get_all_positions(self):
|
||||
items = []
|
||||
positions = self.client.get_all_positions()
|
||||
success, positions = self.call("get_all_positions")
|
||||
if not success:
|
||||
return (success, positions)
|
||||
|
||||
for item in positions:
|
||||
item = dict(item)
|
||||
for item in positions["itemlist"]:
|
||||
item["account_id"] = self.account.id
|
||||
item["unrealized_pl"] = float(item["unrealized_pl"])
|
||||
items.append(item)
|
||||
return items
|
||||
return (True, items)
|
||||
|
||||
@@ -2,9 +2,15 @@ from oandapyV20 import API
|
||||
from oandapyV20.endpoints import accounts, orders, positions, trades
|
||||
|
||||
from core.exchanges import BaseExchange
|
||||
from core.lib.schemas import oanda_s
|
||||
|
||||
OANDA_SCHEMA_MAPPING = {}
|
||||
|
||||
|
||||
class OANDAExchange(BaseExchange):
|
||||
def set_schema(self):
|
||||
self.schema = OANDA_SCHEMA_MAPPING
|
||||
|
||||
def connect(self):
|
||||
self.client = API(access_token=self.account.api_secret)
|
||||
self.account_id = self.account.api_key
|
||||
@@ -53,4 +59,4 @@ class OANDAExchange(BaseExchange):
|
||||
def get_all_positions(self):
|
||||
r = positions.OpenPositions(accountID=self.account_id)
|
||||
self.client.request(r)
|
||||
return r.response["positions"]
|
||||
return (True, [])
|
||||
|
||||
Reference in New Issue
Block a user