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 :

  • 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

  • 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