Skip to content

Commit

Permalink
started oanda api, not done yet
Browse files Browse the repository at this point in the history
  • Loading branch information
arun-annamalai authored and EmersonDove committed Aug 18, 2021
1 parent 4cea662 commit 01420af
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 4 deletions.
9 changes: 7 additions & 2 deletions blankly/exchanges/interfaces/direct_calls_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from blankly.exchanges.interfaces.binance.binance_interface import BinanceInterface
from blankly.exchanges.interfaces.coinbase_pro.coinbase_pro_api import API as CoinbaseProAPI
from blankly.exchanges.interfaces.coinbase_pro.coinbase_pro_interface import CoinbaseProInterface
from blankly.exchanges.interfaces.oanda.oanda_api import OandaAPI
from blankly.exchanges.interfaces.oanda.oanda_interface import OandaInterface


class DirectCallsFactory:
Expand Down Expand Up @@ -55,7 +57,10 @@ def create(exchange_name: str, auth: ABCAuth, preferences_path: str = None):
return calls, AlpacaInterface(calls, preferences_path)

elif exchange_name == 'oanda':
calls = create_alpaca_client(auth, preferences["settings"]["use_sandbox"])
return calls, OandaInterface(calls, preferences_path)
calls = OandaAPI(auth, preferences["settings"]["use_sandbox"])

# TODO: CHANGE THIS BELOW
return calls, None

elif exchange_name == 'paper_trade':
return None, None
121 changes: 119 additions & 2 deletions blankly/exchanges/interfaces/oanda/oanda_api.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,131 @@
from blankly.exchanges.interfaces.oanda.oanda_auth import OandaAuth
import requests
from collections import OrderedDict
from urllib.parse import urlencode


class OandaAPI:
# documentation here: http://developer.oanda.com/rest-live-v20/account-ep/
API_URL = 'https://api-fxtrade.oanda.com'
API_PRACTICE_URL = 'https://api-fxpractice.oanda.com'

def __init__(self, auth: OandaAuth, sandbox: bool = False):
self.api_key = auth.keys['API_KEY']
self.secret_key = auth.keys['API_SECRET']
self.api_key = auth.keys['PERSONAL_ACCESS_TOKEN']

if not sandbox:
self.__api_url = self.API_URL
else:
self.__api_url = self.API_PRACTICE_URL

self.session = self._init_session()

def _init_session(self):
session = requests.session()
session.headers.update({"Content-Type": "application/json",
"Accept-Datetime-Format": "UNIX",
'Authorization': 'Bearer {}'.format(self.api_key)})
return session

def _send_request(self, method, url, params=None, data=None):
if not params:
params = OrderedDict()
else:
assert isinstance(params, OrderedDict)

if not data:
data = OrderedDict()
else:
assert isinstance(data, OrderedDict)

response = getattr(self.session, method)(url, params=params, data=data)
return response.json()

"""
Account Endpoints
"""

def get_all_accounts(self):
endpoint = '/v3/accounts'
return self._send_request('get', self.__api_url + endpoint)

def get_account(self, accountid: str):
assert isinstance(accountid, str)
endpoint = f'/v3/accounts/{accountid}'
return self._send_request('get', self.__api_url + endpoint)

def get_account_summary(self, accountid: str):
assert isinstance(accountid, str)
endpoint = f'/v3/accounts/{accountid}/summary'
return self._send_request('get', self.__api_url + endpoint)

def get_account_instruments(self, accountid: str):
assert isinstance(accountid, str)
endpoint = f'/v3/accounts/{accountid}/instruments'
return self._send_request('get', self.__api_url + endpoint)

def get_account_changes(self, accountid: str, sinceTransactionID: str):
assert isinstance(accountid, str)
endpoint = f'/v3/accounts/{accountid}/changes'

params = OrderedDict()
params["sinceTransactionID"] = sinceTransactionID

return self._send_request('get', self.__api_url + endpoint, params=params)

def patch_account_configuration(self, accountid: str, alias: str, marginRate: float):
# Client-defined alias (name) for the Account
# alias: (string),
# The string representation of a decimal number.
# marginRate: (DecimalNumber)

assert isinstance(accountid, str)
assert isinstance(alias, str)
assert isinstance(marginRate, float)
endpoint = f'/v3/accounts/{accountid}/configuration'

data = OrderedDict()
data["alias"] = alias
data["marginRate"] = marginRate

return self._send_request('patch', self.__api_url + endpoint, data=data)

"""
Instrument Endpoints
"""
def get_candles(self, instrument: str):
endpoint = f'/v3/instruments/{instrument}/candles'
return self._send_request('get', self.__api_url + endpoint)

def get_order_book(self, instrument: str):
assert isinstance(instrument, str)
endpoint = f'/v3/instruments/{instrument}/orderBook'
return self._send_request('get', self.__api_url + endpoint)

def get_position_book(self, instrument: str):
assert isinstance(instrument, str)
endpoint = f'/v3/instruments/{instrument}/positionBook'
return self._send_request('get', self.__api_url + endpoint)

"""
Order Endpoints
"""

"""
Trade Endpoints
"""

"""
Position Endpoints
"""

"""
Transaction Endpoints
"""

"""
Pricing Endpoints
"""

"""
Forex Labs Endpoints
"""
9 changes: 9 additions & 0 deletions blankly/exchanges/interfaces/oanda/oanda_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from blankly.exchanges.interfaces.exchange_interface import ExchangeInterface
from blankly.exchanges.interfaces.oanda.oanda_api import OandaAPI


class OandaInterface(ExchangeInterface):
def __init__(self, authenticated_API: OandaAPI, preferences_path: str):
super().__init__('oanda', authenticated_API, preferences_path)
assert isinstance(self.calls, OandaAPI)

8 changes: 8 additions & 0 deletions examples/keys_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,13 @@
"API_KEY": "********************",
"API_SECRET": "****************************************"
}
},
"oanda": {
"oanda portfolio": {
"PERSONAL_ACCESS_TOKEN": "********************",
},
"oanda portfolio 2": {
"PERSONAL_ACCESS_TOKEN": "********************",
}
}
}
43 changes: 43 additions & 0 deletions tests/exchanges/interfaces/oanda/test_oanda_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import datetime
import time
from datetime import datetime as dt
from pathlib import Path

import pytest
import pytz

from blankly.exchanges.interfaces.oanda.oanda_api import OandaAPI
from blankly.exchanges.interfaces.oanda.oanda_auth import OandaAuth
from blankly.exchanges.interfaces.oanda.oanda_interface import OandaInterface
from blankly.exchanges.interfaces.direct_calls_factory import DirectCallsFactory

timeZ_Ny = pytz.timezone('America/New_York')
MARKET_OPEN = datetime.time(hour=9, minute=0, second=0, tzinfo=timeZ_Ny)
MARKET_CLOSE = datetime.time(hour=17, minute=0, second=0, tzinfo=timeZ_Ny)


@pytest.fixture
def oanda_interface():
keys_file_path = Path("tests/config/keys.json").resolve()
settings_file_path = Path("tests/config/settings.json").resolve()

auth_obj = OandaAuth(str(keys_file_path), "oanda test portfolio")
_, oanda_interface = DirectCallsFactory.create("oanda", auth_obj, str(settings_file_path))
return oanda_interface


def test_get_exchange(oanda_interface: OandaInterface) -> None:
assert oanda_interface.get_exchange_type() == 'oanda'

def test_api() -> None:
keys_file_path = Path("tests/config/keys.json").resolve()
settings_file_path = Path("tests/config/settings.json").resolve()

auth_obj = OandaAuth(str(keys_file_path), "oanda test portfolio")
api, _ = DirectCallsFactory.create("oanda", auth_obj, str(settings_file_path))
assert isinstance(api, OandaAPI)
print(api.get_all_accounts())
print(api.get_account('101-001-20168332-001'))
print(api.get_account_summary('101-001-20168332-001'))
print(api.get_account_instruments('101-001-20168332-001'))
print(api.get_account_changes('101-001-20168332-001', 3))

0 comments on commit 01420af

Please sign in to comment.