Beyond Getting Started¶
So you have read Using async_v20 and need to know more.
Your first issue is knowing what methods to use.
The OandaClient API docs contains all the exposed methods async_v20 provides.
What you need to know¶
- OandaClient returns v20 API calls in
Response
objects The response is a python dictionary and designed to reflect the responses defined by the v20 docs :
- responses contain the equivalent python objects. As defined in Class Definitions
- OandaClient returns v20 API calls in
OandaClient. Automatically supplys arguments to endpoints that require the following:
-
class
async_v20.definitions.primitives.
AccountID
[source] Bases:
str
,async_v20.definitions.primitives.Primitive
The string representation of an Account Identifier.
-
class
async_v20.endpoints.annotations.
Authorization
[source] Bases:
str
Contains OANDA’s v20 API authorization token
-
class
async_v20.endpoints.annotations.
LastTransactionID
[source] Bases:
async_v20.definitions.primitives.TransactionID
Contains the most recent TransactionID
-
class
async_v20.endpoints.annotations.
SinceTransactionID
[source] Bases:
async_v20.definitions.primitives.TransactionID
The account changes to get Since LastTransactionID for account_changes() method
-
class
- OandaClient by default will connect to the practice server:
- OANDA’s docs Contain host information
Underling Principles¶
All arguments passed to OandaClient API methods are used to create instances of the parameters annotation. Why is this useful?
- Prevents you from importing required class’ and instantiating them manually
- HTTP requests are formatted based upon the objects the endpoint accepts. See How Are Arguments Passed
- The base class
Model
will convert the object into valid JSON- Invalid arguments will raise
InvalidValue
catching mistakes earlier- Provides flexibility when passing arguments
Here is an Example
import asyncio
from async_v20 import OandaClient
client = OandaClient()
# This
coroutine_1 = client.create_order('AUD_USD', 10)
# Is the same as this
from async_v20 import InstrumentName, DecimalNumber
coroutine_2 = client.create_order(
InstrumentName('AUD_USD'), DecimalNumber(10)
)
# Is the same as this
from async_v20 import OrderRequest
coroutine_3 = client.post_order(
order_request=OrderRequest(
instrument='AUD_USD', units=10, type='MARKET'
)
)
loop = asyncio.get_event_loop()
loop.run_until_complete(
asyncio.gather(
coroutine_1,
coroutine_2,
coroutine_3
)
)
Note
Executing this example will create a long position of the AUD/USD currency pair worth 30 units.
What might be useful¶
How Are Arguments Passed¶
All methods exposed by async_v20. OandaClient are written in a declarative fashion.
Lets take at look at an example:
class InstrumentInterface(object):
@endpoint(GETInstrumentsCandles)
def get_candles(self,
instrument: InstrumentName,
price: PriceComponent = 'M',
granularity: CandlestickGranularity = 'S5',
count: Count = sentinel,
from_time: FromTime = sentinel,
to_time: ToTime = sentinel,
smooth: Smooth = False,
include_first_query: IncludeFirstQuery = sentinel,
daily_alignment: DailyAlignment = 17,
alignment_timezone: AlignmentTimezone = 'America/New_York',
Note
- The docstring has been left of this example for brevity.
- This example is not complete without a pass statement
- First
- We define the endpoint:
class InstrumentInterface(object):
- Then
- We define arguments to pass to the endpoint
class InstrumentInterface(object): @endpoint(GETInstrumentsCandles) def get_candles(self, instrument: InstrumentName, price: PriceComponent = 'M', granularity: CandlestickGranularity = 'S5', count: Count = sentinel, from_time: FromTime = sentinel, to_time: ToTime = sentinel, smooth: Smooth = False, include_first_query: IncludeFirstQuery = sentinel, daily_alignment: DailyAlignment = 17, alignment_timezone: AlignmentTimezone = 'America/New_York',
You will notice that all arguments have an annotation.
async_v20 uses these annotations to format arguments into the correct http request.
The http request formatting is defined by the EndPoint
In this case
class GETInstrumentsCandles(EndPoint): # the HTTP verb to use for this endpoint method = 'GET' # path to endpoint path = ('/v3/instruments/', InstrumentName, '/candles') # description of endpoint description = 'Fetch candlestick data for an instrument.' # parameters required to send to endpoint parameters = {Authorization: (HEADER, 'Authorization'), AcceptDatetimeFormat: (HEADER, 'Accept-Datetime-Format'), InstrumentName: (PATH, 'instrument'), PriceComponent: (QUERY, 'price'), CandlestickGranularity: (QUERY, 'granularity'), Count: (QUERY, 'count'), FromTime: (QUERY, 'from'), ToTime: (QUERY, 'to'), Smooth: (QUERY, 'smooth'), IncludeFirstQuery: (QUERY, 'includeFirst'), DailyAlignment: (QUERY, 'dailyAlignment'), AlignmentTimezone: (QUERY, 'alignmentTimezone'), WeeklyAlignment: (QUERY, 'weeklyAlignment')} # valid responses responses = { 200: {'instrument': InstrumentName, 'granularity': CandlestickGranularity, 'candles': ArrayCandlestick}} # error msgs' error = (400, 401, 404, 405)
Notice that
parameters = {Authorization: (HEADER, 'Authorization'), AcceptDatetimeFormat: (HEADER, 'Accept-Datetime-Format'),
Contains key entries that coincide with the methods annotations. The annotation is then used to lookup up location of the argument in the HTTP request and the corresponding key that will be used with the passed data to create the correct key/value pair.
How Responses are Constructed¶
The http response from OANDA is handled by the EndPoint each OandaClient. method defines.
- There is a two step process by which the response is constructed:
- The http status is used to look up the expected response
- Each JSON object is constructed into the appropriate python object
How Objects are Serialized¶
One of the main problems async_v20 solves for you is correctly formatting objects into JSON that OANDA’s v20 API accepts.
The issue here is that OANDA defines objects with camelCase attributes. Python programs typically reserve camelCase for class definitions.
This means, in order to both satisfy python standards and OANDA, objects (as defined in Class Definitions) need to accept camelCase and snake_case arguments when being constructed.
Objects store there attributes as snake_case (as python programmers would expect), which adds a further requirement to convert these into camelCase when being serialized.
To solve this the async_v20.definitions.attributes
module
contains two dictionaries. instance_attributes
& json_attributes
:
- When creating objects, arguments are passed through instance_attributes dictionary
- When serializing objects, attributes are passed through json_attributes dictionary