-
Notifications
You must be signed in to change notification settings - Fork 267
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4cea662
commit 01420af
Showing
5 changed files
with
186 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |