fisk/core/exchanges/oanda.py

172 lines
5.6 KiB
Python
Raw Normal View History

2022-10-30 10:57:53 +00:00
from oandapyV20 import API
from oandapyV20.endpoints import accounts, orders, positions, pricing, trades
2022-10-30 11:21:48 +00:00
2022-12-13 07:20:49 +00:00
from core.exchanges import BaseExchange, common
2022-10-30 11:21:48 +00:00
2022-10-30 10:57:53 +00:00
class OANDAExchange(BaseExchange):
2022-11-04 07:20:55 +00:00
def call_method(self, request):
self.client.request(request)
response = request.response
if isinstance(response, list):
response = {"itemlist": response}
2022-11-04 07:20:55 +00:00
return response
2022-10-30 10:57:53 +00:00
def connect(self):
self.client = API(access_token=self.account.api_secret)
self.account_id = self.account.api_key
2022-10-30 11:21:48 +00:00
def get_account(self):
r = accounts.AccountDetails(self.account_id)
return self.call(r)
2022-10-30 11:21:48 +00:00
def get_instruments(self):
r = accounts.AccountInstruments(accountID=self.account_id)
response = self.call(r)
return response
def get_currencies(self, currencies):
params = {"instruments": ",".join(currencies)}
r = pricing.PricingInfo(accountID=self.account_id, params=params)
response = self.call(r)
return response
def get_supported_assets(self, response=None):
if not response:
response = self.get_instruments()
return [x["name"] for x in response["itemlist"]]
2022-10-30 10:57:53 +00:00
2023-01-11 19:46:47 +00:00
def get_balance(self, return_usd=False):
r = accounts.AccountSummary(self.account_id)
response = self.call(r)
2022-12-13 07:20:49 +00:00
balance = float(response["balance"])
2023-01-11 19:46:47 +00:00
currency = response["currency"]
balance_usd = common.to_currency("sell", self.account, balance, currency, "USD")
2022-12-13 07:20:49 +00:00
common.get_balance_hook(
self.account.user.id,
self.account.user.username,
self.account.id,
self.account.name,
2023-01-11 19:46:47 +00:00
balance_usd,
2022-12-13 07:20:49 +00:00
)
2023-01-11 19:46:47 +00:00
if return_usd:
return balance_usd
2022-12-13 07:20:49 +00:00
return balance
2022-10-30 10:57:53 +00:00
def get_market_value(self, symbol):
raise NotImplementedError
def post_trade(self, trade):
if trade.direction == "sell":
amount = -trade.amount
else:
amount = trade.amount
data = {
"order": {
# "price": "1.5000", - added later
"timeInForce": trade.time_in_force.upper(),
"instrument": trade.symbol,
"units": str(amount),
"type": trade.type.upper(),
"positionFill": "DEFAULT",
}
}
if trade.stop_loss is not None:
data["order"]["stopLossOnFill"] = {
"timeInForce": "GTC",
"price": str(trade.stop_loss),
}
if trade.take_profit is not None:
data["order"]["takeProfitOnFill"] = {"price": str(trade.take_profit)}
if trade.price is not None:
if trade.type == "limit":
data["order"]["price"] = str(trade.price)
elif trade.type == "market":
data["order"]["priceBound"] = str(trade.price)
2022-11-15 07:20:17 +00:00
if trade.trailing_stop_loss is not None:
data["order"]["trailingStopLossOnFill"] = {
"distance": str(trade.trailing_stop_loss),
"timeInForce": "GTC",
}
r = orders.OrderCreate(self.account_id, data=data)
response = self.call(r)
trade.response = response
trade.status = "posted"
trade.order_id = str(int(response["id"]) + 1)
trade.client_order_id = response["requestID"]
trade.save()
return response
2022-10-30 10:57:53 +00:00
2023-01-02 18:42:03 +00:00
def close_trade(self, trade_id):
"""
Close a trade.
"""
r = trades.TradeClose(accountID=self.account_id, tradeID=trade_id)
return self.call(r)
2022-10-30 10:57:53 +00:00
def get_trade(self, trade_id):
# OANDA is off by one...
r = trades.TradeDetails(accountID=self.account_id, tradeID=trade_id)
return self.call(r)
2022-10-30 10:57:53 +00:00
def update_trade(self, trade):
raise NotImplementedError
2022-11-04 07:20:55 +00:00
# r = orders.OrderReplace(
# accountID=self.account_id, orderID=trade.order_id, data=data
# )
# self.client.request(r)
# return r.response
2022-10-30 10:57:53 +00:00
def cancel_trade(self, trade_id):
raise NotImplementedError
2022-11-02 18:25:34 +00:00
def get_position_info(self, symbol):
r = positions.PositionDetails(self.account_id, symbol)
response = self.call(r)
response["account"] = self.account.name
response["account_id"] = self.account.id
return response
2022-10-30 10:57:53 +00:00
def get_all_positions(self):
2022-11-02 18:25:34 +00:00
items = []
2022-10-30 11:21:48 +00:00
r = positions.OpenPositions(accountID=self.account_id)
2022-11-04 07:20:55 +00:00
response = self.call(r)
2022-11-02 18:25:34 +00:00
for item in response["itemlist"]:
item["account"] = self.account.name
2022-11-02 19:04:05 +00:00
item["account_id"] = self.account.id
2022-11-02 18:25:34 +00:00
item["unrealized_pl"] = float(item["unrealized_pl"])
items.append(item)
2022-11-04 07:20:55 +00:00
return items
2022-11-14 18:29:07 +00:00
2022-12-22 07:20:49 +00:00
def get_all_open_trades(self):
r = trades.OpenTrades(accountID=self.account_id)
2023-01-11 19:46:47 +00:00
return self.call(r)["itemlist"]
2022-12-22 07:20:49 +00:00
def close_position(self, side, symbol):
data = {
f"{side}Units": "ALL",
}
r = positions.PositionClose(
accountID=self.account_id, instrument=symbol, data=data
)
response = self.call(r)
return response
2022-11-14 18:29:07 +00:00
def close_all_positions(self):
2023-01-05 17:25:06 +00:00
all_positions = self.get_all_positions()
responses = []
for position in all_positions:
side = position["side"]
symbol = position["symbol"]
data = {
f"{side}Units": "ALL",
}
r = positions.PositionClose(
accountID=self.account_id, instrument=symbol, data=data
)
response = self.call(r)
responses.append(response)
return responses