Forex Trading Diary #1 - Automated Forex Trading With The OANDA API Forex Trading Api
I before mentioned in the QuantStart: 2014 In Review article that I would exist spending some on 2015 script about automated forex trading.
Given that I myself usually take out research in equities and futures markets, I thought it would exist amusement (and educational!) to copy about my experiences on entering the forex fair in the style on a diary. Each "diary entry" will attempt to build on top of everything those before, however should also exist relatively self-contained.
In this earliest admission on the log I'll exist describing how to place up a new use brokerage report in the company of OANDA as well as how to cause a basic multithreaded event-driven trading engine that can automatically execute trades in both a use and board setting.
Last year we spent a lot on while looking at the event-driven backtester, primarily for equities and ETFs. The only I present below is geared towards forex and can exist used for either paper trading or live trading.
I have written everything on the next instructions for Ubuntu 14.04, however they should easily translate to Windows or Mac OS X, using a Python distribution such as Anaconda. The only extra library used for the Python trading engine is the requests library, which is demanded for HTTP contact to the OANDA API.
Since this is the earliest stake directly about foreign exchange trading, and the rules presented below can exist straightforwardly adapted to a board trading environment, I would like to present the next disclaimers:
Disclaimer: Trading foreign exchange on top of margin carries a high level on risk, and may not exist right for everything investors. Past performance is not indicative on future results. The high measure on leverage can work against you as well as for you. Before deciding to invest in foreign exchange you should carefully consider your backing objectives, level on experience, and risk appetite. The possibility exists that you could sustain a loss on some or everything on your initial backing and therefore you should not invest money that you cannot afford to lose. You should exist aware on everything the risks associated in the company of foreign exchange trading, and seek advice from an independent financial advisor if you have a scrap of of} doubts.
This computer program is provided "as is" and a scrap of of} expressed or implied warranties, including, however not restricted to, the implied warranties on merchantability and fitness for a special purpose are disclaimed. In not at all incident shall the regents or contributors exist liable for a scrap of of} direct, indirect, incidental, special, exemplary, or consequential damages (including, however not restricted to, procurement on substitute stock or services; loss on use, data, or profits; or trade interruption) but caused and on top of a scrap of of} theory on liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in a scrap of of} out on the utilize on this software, even if advised on the possibility on such damage.
Setting Up an Account in the company of OANDA
The earliest enquiry that comes to mind is "Why take OANDA?". Simply put, at the end of a slice on Googling approximately for forex brokers that had APIs, I maxim that OANDA had recently released a actual REST API that could easily exist communicated in the company of from nearly a scrap of of} language in an very easy manner. After reading by way of their developer API documentation, I decided to give them a try, at least in the company of a use account.
To exist clear - I have not at all prior or existing relationship in the company of OANDA and am only if this recommendation based on top of my restricted knowledge playing approximately in the company of their use API and some fast terminology (for fair facts download) during the time that working at a reserve previously. If anybody has come on the other or far side of a scrap of of} other forex brokers that also have a the same modern API at that time I'd exist happy to give them a look as well.
Before utilising the API it is demanded to sign up for a use account. To work this, head to the sign-up link. You will see the next screen:
OANDA sign-up screen
You will at that time exist capable to sign in in the company of your login credentials. Make positive to take the "fxTradePractice" tag from the sign-in screen:
OANDA sign-in screen
Once in you will need to produce a message on your Account ID. It is listed underneath the black "My Funds" header next to "Primary". Mine is a 7-digit number. In supplement you will also need to generate a own API token. To work this beat "Manage API Access" underneath the "Other Actions" tag on top of the lower left:
OANDA dashboard
At this leg you will exist capable to generate an API token. You will need the key for utilize later, thus produce positive to copy it down as well.
You will at the moment wish for to launch the FXTrade Practice application, which will allow us to see the executed orders and our (paper!) profit & loss.
If you are running a Ubuntu system you will need to put in a slightly dissimilar variety on Java. In particular, the Oracle variety on Java 8. If you don't work this at that time the use simulator will not stuff from the browser. I ran these commands on top of my system:
sudo add-apt-repository ppa:webupd8team/java sudo apt-get update sudo apt-get put in oracle-java8-installer
You will at the moment exist capable to launch the use trading environment. Return to the OANDA dashboard and beat the green highlighted "Launch FXTrade Practice" link. It will take up a Java dialog asking whether you wish for to run it. Click "Run" and the fxTrade Practice tool will load. Mine defaulted to a 15-min candle diagram on EUR/USD in the company of the Quote Panel on top of the left:
OANDA fxTrade Practice screen
At this essence we are ready to commence plotting and coding our mechanical forex trading system against the OANDA API.
Overview on Trading Architecture
If you have been next the event-driven backtester series for equities and ETFs that I created preceding year, you'll exist aware on how such an event-driven trading system functions. For those on you who are new to event-driven software, I would strongly suggest reading by way of the article in instruct to gain some insight into how they work.
In essence, the continuous program is executed in an infinte while
loop that only terminates when the trading system is close off. The inner contact mechanism on the program is given via a queue that contains events.
The line is continuously queried to check for new events. Once an incident has been taken out the top on the line it must exist handled by an appropriate part on the program. Hence a fair facts cater for might cause TickEvent
s that are placed onto the line when a new fair cost arrives. A signal-generating policy object might cause OrderEvent
s that are to exist sent to a brokerage.
The helpfulness on such a system is given by the fact that it doesn't thing what instruct or types on events are placed on top of the queue, as they will always exist correctly handled by the true part within the program.
In supplement dissimilar parts on the program can exist run in unconnected threads, meaning that there is not once a scrap of of} waiting for a scrap of of} special part before processing a scrap of of} other. This is very helpful in algorithmic trading situations where fair facts cater for handlers and policy flare generators have vastly dissimilar performance characteristics.
The main trading loop is given by the next Python pseudo-code:
while True: try: incident = events_queue.get(False) apart from Queue.Empty: pass else: if incident is not None: if event.type == 'TICK': strategy.calculate_signals(event) elif event.type == 'ORDER': execution.execute_order(event) time.sleep(heartbeat)
As we stated above the rules runs in an vast loop. Firstly, the line is polled to retrieve a new event. If the line is empty, at that time the loop simply restarts at the end of a short sleep period famous as the "heartbeat". If an incident is start its sort is assessed and at that time the relevant module (either the strategy
or the execution
handler) is called upon to grip the incident and maybe generate new ones that go back onto the queue.
The basic components that we will cause for our trading system contain the following:
- Streaming Price Handler - This will remain a long-running connection unlocked to OANDAs servers and send tick facts (i.e. bid/ask) on the other or far side of the connection for a scrap of of} instruments that we're interested in.
- Strategy Signal Generator - This will grip a sequence on tick events and utilize them to generate trading orders that will exist executed by the execution handler.
- Execution Handler - Takes a place on instruct events and at that time blindly executes them in the company of OANDA.
- Events - These objects constitute the "messages" that are passed approximately on top of the events queue. We only need two for this implementation, namely the
TickEvent
and theOrderEvent
. - Main Entry Point - The main admission essence also includes the "trade" loop that continuously polls the message line and dispatches messages to the correct component. This is often famous as the "event loop" or "event handler".
We will at the moment discuss the carrying out on the rules in detail. At the bottom on the article is the complete listing on everything source rules files. If you place them in the same directory and run python trading.py
you will commence generating orders, assuming you have filled in your report ID and authentication token from OANDA.
Python Implementation
It is damaging use to shop passwords or authentication keys within a codebase as you can at not at all time predict who will eventually exist allowed access to a project. In a production system we would shop these credentials as environment variables in the company of the system and at that time query these "envvars" every while the rules is redeployed. This ensures that passwords and auth tokens are at not at all time stored in a variety control system.
However, since we are solely interested in building a "toy" trading system, and are not concerned in the company of production details in this article, we will instead unconnected these auth tokens into a settings file.
In the next settings.py
configuration folder we have a dictionary called ENVIRONMENTS
which stores the API endpoints for both the OANDA cost streaming API and the trading API. Each sub dictionary contains three unconnected API endpoints: real
, practice
and sandbox
.
The sandbox
API is purely for trying rules and for checking that there are not at all errors or bugs. It does not have the uptime guarantees on the real
or practice
APIs. The practice
API, in essence, provides the ability to paper trade. That is, it provides everything on the features on the real
API on top of a simulated use account. The real
API is just that - it is board trading! If you utilize that endpoint in your code, it will trade against your board report balance. BE EXTREMELY CAREFUL!
IMPORTANT: When trading against the use API recall that an critical transaction cost, that on market impact, is not considered. Since not at all trades are really being placed into the setting this cost must exist accounted for in an extra way away using a fair impact model if you wish to realistically assess performance.
In the next we are using the practice
report as given by the DOMAIN
setting. We need two unconnected dictionaries for the domains, only every for the streaming and trading API components. Finally we have the ACCESS_TOKEN
and ACCOUNT_ID
. I've filled the two below in the company of dummy IDs thus you will need to utilise your own, which can exist accessed from the OANDA report page:
ENVIRONMENTS = "streaming": "real": "stream-fxtrade.oanda.com", "practice": "stream-fxpractice.oanda.com", "sandbox": "stream-sandbox.oanda.com" , "api": "real": "api-fxtrade.oanda.com", "practice": "api-fxpractice.oanda.com", "sandbox": "api-sandbox.oanda.com" DOMAIN = "practice" STREAM_DOMAIN = ENVIRONMENTS["streaming"][DOMAIN] API_DOMAIN = ENVIRONMENTS["api"][DOMAIN] ACCESS_TOKEN = 'abcdef0123456abcdef0123456-abcdef0123456abcdef0123456' ACCOUNT_ID = '12345678'
The next pace is to outline the events that the line will utilize to help everything on the separate components communicate. We need two: TickEvent
and OrderEvent
. The earliest stores information about instrument fair facts such as the (best) bid/ask and the trade time. The second is used to transmit orders to the execution handler and thus contains the instrument, the numeral on units to trade, the instruct sort ("market" or "limit") and the "side" (i.e. "buy" and "sell").
To future-proof our events rules we are accepted to cause a base class called Event
and have everything events inherit from this. The rules is provided below in events.py
:
class Event(object): pass class TickEvent(Event): def __init__(self, instrument, time, bid, ask): self.type = 'TICK' self.instrument = instrument self.time = time self.bid = bid self.ask = ask class OrderEvent(Event): def __init__(self, instrument, units, order_type, side): self.type = 'ORDER' self.instrument = instrument self.units = units self.order_type = order_type self.side = side
The next class we are accepted to cause will grip the trading strategy. In this demo we are accepted to cause a rather nonsensical policy that simply receives everything on the fair ticks and on top of each and every 5th tick randomly buys or sells 10,000 units on EUR/USD.
Clearly this is a ridiculous "strategy"! However, it is fantastic for trying purposes because it is easy to rules and understand. In future log entries we will exist replacing this in the company of something significantly more exciting that will (hopefully) swing round a profit!
The strategy.py
folder can exist start below. Let's work by way of it and see what's accepted on. Firstly we buy in the random
library and the OrderEvent
object from events.py
. We need the random
lib in instruct to take a chance purchase or trade order. We need OrderEvent
as this is how the policy object will send orders to the events queue, which will after exist executed by the execution handler.
The TestRandomStrategy
class simply takes the instrument (in this situation EUR/USD), the numeral on units and the events line as a place on parameters. It at that time creates a ticks
counter that is used to tell how many TickEvent
instances it has seen.
Most on the work occurs in the calculate_signals
method, which simply takes an event, determines whether it is a TickEvent
(otherwise ignore) and increments the tick counter. It at that time checks to see if the add (up) is dividable by 5 and at that time randomly buys or sells, in the company of a fair order, the specified numeral on units. It's certainly not the world's greatest trading strategy, however it will exist more than right for our OANDA brokerage API trying purposes!
import random from incident buy in OrderEvent class TestRandomStrategy(object): def __init__(self, instrument, units, events): self.instrument = instrument self.units = units self.events = events self.ticks = 0 def calculate_signals(self, event): if event.type == 'TICK': self.ticks += 1 if self.ticks % 5 == 0: margin = random.choice(["buy", "sell"]) instruct = OrderEvent( self.instrument, self.units, "market", side ) self.events.put(order)
The next part is the execution handler. This class is tasked in the company of acting upon OrderEvent
instances and making requests to the broker (in this situation OANDA) in a "dumb" fashion. That is, there is not at all risk control or potfolio construction overlay. The execution handler will simply execute a scrap of of} instruct that it has been given.
We must go by or past everything on the authentication information to the Execution
class, including the "domain" (practice, real or sandbox), the access token and report ID. We at that time cause a secure connection in the company of httplib
, only on Pythons built in libraries.
Most on the work occurs in execute_order
. The method requires an incident as a parameter. It at that time constructs two dictionaries - the headers
and the params
. These dictionaries will at that time exist correctly encoded (partially by urllib
, an extra Python library) to exist sent as an HTTP POST request to OANDAs API.
We overtake the Content-Type
and Authorization
header parameters, which contain our authentication information. In supplement we encode the parameters, which contain the instrument (EUR/USD), units, instruct sort and margin (buy/sell). Finally, we produce the request and save the response:
import httplib import urllib class Execution(object): def __init__(self, domain, access_token, account_id): self.domain = domain self.access_token = access_token self.account_id = account_id self.conn = self.obtain_connection() def obtain_connection(self): go back httplib.HTTPSConnection(self.domain) def execute_order(self, event): headers = "Content-Type": "application/x-www-form-urlencoded", "Authorization": "Bearer " + self.access_token params = urllib.urlencode( "instrument" : event.instrument, "units" : event.units, "type" : event.order_type, "side" : event.side ) self.conn.request( "POST", "/v1/accounts/%s/orders" % str(self.account_id), params, headers ) answer = self.conn.getresponse().read() publish response
The nearly all compound part on the trading system is the StreamingForexPrices
object, which handles the fair cost updates from OANDA. There are two methods: connect_to_stream
and stream_to_queue
.
The earliest method uses the Python requests library to connect to a streaming socket in the company of the appropriate headers and parameters. The parameters contain the Account ID and the demanded instrument record that should exist listened to for updates (in this situation it is only EUR/USD). Note the next line:
resp = s.send(pre, stream=True, verify=False)
This tells the connection to exist streamed and thus kept unlocked in a long-running manner.
The second method, stream_to_queue
, really attempts to connect to the stream. If the answer is not successful (i.e. the answer rules is not HTTP 200), at that time we simply go back and exit. If it is successful we attempt to stuff the JSON box returned into a Python dictionary. Finally, we turn the Python dictionary in the company of the instrument, bid/ask and timestamp into a TickEvent
that is sent to the events queue:
import requests import json from incident buy in TickEvent class StreamingForexPrices(object): def __init__( self, domain, access_token, account_id, instruments, events_queue ): self.domain = domain self.access_token = access_token self.account_id = account_id self.instruments = instruments self.events_queue = events_queue def connect_to_stream(self): try: s = requests.Session() url = "https://" + self.domain + "/v1/prices" headers = 'Authorization' : 'Bearer ' + self.access_token params = 'instruments' : self.instruments, 'accountId' : self.account_id req = requests.Request('GET', url, headers=headers, params=params) pre = req.prepare() resp = s.send(pre, stream=True, verify=False) go back resp apart from Exception as e: s.close() publish "Caught departure when connecting to stream\n" + str(e) def stream_to_queue(self): answer = self.connect_to_stream() if response.status_code != 200: return for mark in response.iter_lines(1): if line: try: msg = json.loads(line) apart from Exception as e: publish "Caught departure when converting message into json\n" + str(e) return if msg.has_key("instrument") or msg.has_key("tick"): publish msg instrument = msg["tick"]["instrument"] while = msg["tick"]["time"] bid = msg["tick"]["bid"] ask = msg["tick"]["ask"] tev = TickEvent(instrument, time, bid, ask) self.events_queue.put(tev)
We at the moment have everything on the vital components in place. The final pace is to wrap up everything we have written thus far into a "main" program. The goal on this file, famous as trading.py
, is to cause two unconnected threads, only on which runs the pricing handler and the other which runs the trading handler.
Why work we need two unconnected threads? Put simply, we are executing two "separate" pieces on code, both on which are continuously running. If we were to cause a non-threaded program, at that time the streaming socket used for the pricing updates would not once ever "release" back to the main rules path and thus we would never really take out a scrap of of} trading. Similarly, if we ran the trade
loop (see below), we would at not at all time really go back the flow path to the cost streaming socket. Hence we need multiple threads, only for every component, thus that they can exist carried out independently. They will both talk to every other via the events queue.
Let's examine this a slice futher. We cause two unconnected threads in the company of the next lines:
trade_thread = threading.Thread(target=trade, args=(events, strategy, execution)) price_thread = threading.Thread(target=prices.stream_to_queue, args=[])
We go by or past the function or method name to the target
keyword case and at that time overtake an iterable (such as a record or tuple) to the args
keyword argument, which at that time passes those arguments to the actual method/function.
Finally we start both threads in the company of the next lines:
trade_thread.start() price_thread.start()
Thus we are capable to run two, effectively vast looping, rules segments independently, which both talk by way of the events queue. Note that the Python threading
library does not produce a right multi-core multithreaded setting due to the CPython carrying out on Python and the Global Interpreter Lock (GIL). If you would like to read more about multithreading on top of Python, please grip a look at this article.
Let's examine the sleep on the rules in detail. Firstly we buy in everything on the demanded libraries including Queue
, threading
and time
. We at that time buy in everything on the above rules files. I personally prefer to capitalise a scrap of of} configuration settings, which is a custom I picked up from employed in the company of Django!
After that we outline the trade
function, which was explained in Python-pseudocode above. An vast during the time that loop is carried out (while True:
) that continuously polls from the events line and only skips the loop if it is start empty. If an incident is start at that time it is either a TickEvent
or a OrderEvent
and at that time the appropriate part is called to take it out. In this situation it is either a policy or execution handler. The loop at that time simply sleeps for "heartbeat" seconds (in this situation 0.5 seconds) and continues.
Finally, we outline the main entrypoint on the rules in the __main__
function. It is well commented below, however I will summarise here. In fundamental nature we instantiate the events line and outline the instruments/units. We at that time cause the StreamingForexPrices
cost streaming class and at that time subsequently the Execution
execution handler. Both get the demanded authentication details that are given by OANDA when creating an account.
We at that time cause the TestRandomStrategy
instance. Finally we outline the two threads and at that time start them:
import Queue import threading import time from execution buy in Execution from settings buy in STREAM_DOMAIN, API_DOMAIN, ACCESS_TOKEN, ACCOUNT_ID from policy buy in TestRandomStrategy from streaming buy in StreamingForexPrices def trade(events, strategy, execution): """ Carries out an vast during the time that loop that polls the events line and directs every incident to either the policy part on the execution handler. The loop will at that time pause for "heartbeat" seconds and continue. """ during the time that True: try: incident = events.get(False) apart from Queue.Empty: pass else: if incident is not None: if event.type == 'TICK': strategy.calculate_signals(event) elif event.type == 'ORDER': publish "Executing order!" execution.execute_order(event) time.sleep(heartbeat) if __name__ == "__main__": heartbeat = 0.5 # Half a second between polling events = Queue.Queue() # Trade 10000 units on EUR/USD instrument = "EUR_USD" units = 10000 # Create the OANDA fair cost streaming class # making positive to provide authentication commands prices = StreamingForexPrices( STREAM_DOMAIN, ACCESS_TOKEN, ACCOUNT_ID, instrument, events ) # Create the execution handler making positive to # provide authentication commands execution = Execution(API_DOMAIN, ACCESS_TOKEN, ACCOUNT_ID) # Create the strategy/signal generator, fleeting the # instrument, quantity on units and the events queue policy = TestRandomStrategy(instrument, units, events) # Create two unconnected threads: One for the trading loop # and an extra for the fair cost streaming class trade_thread = threading.Thread(target=trade, args=(events, strategy, execution)) price_thread = threading.Thread(target=prices.stream_to_queue, args=[]) # Start both threads trade_thread.start() price_thread.start()
To run the rules you simply need to place everything the files in the same directory and name the next at the terminal:
python trading.py
Note that to stop the rules at this leg requires a hard slay on the Python process, via "Ctrl-Z" or equivalent! I've not added an extra fibre to grip looking for the sys.exit()
that would exist needed to stop the rules safely. A possible way to stop the rules on top of a Ubuntu/Linux machine is to type:
pgrep python
And at that time pass the production on this (a process number) into the following:
kill -9 PROCESS_ID
Where PROCESS_ID must exist replaced in the company of the production on pgrep. Note that this is NOT expressly good practice!
In after articles we will exist creating a more sophisticated stop/start mechanism that makes utilize on Ubuntu's process supervision in instruct to have the trading system running 24/7.
The production at the end of 30 seconds or so, depending upon the while on day relation to the main trading hours for EUR/USD, for the above code, is given below:
u'tick': u'ask': 1.16283, u'instrument': u'EUR_USD', u'bid': 1.1627, u'time': u'2015-01-19T15:28:19.563256Z' u'tick': u'ask': 1.16287, u'instrument': u'EUR_USD', u'bid': 1.16274, u'time': u'2015-01-19T15:28:28.021045Z' u'tick': u'ask': 1.16287, u'instrument': u'EUR_USD', u'bid': 1.16273, u'time': u'2015-01-19T15:28:30.982725Z' u'tick': u'ask': 1.16285, u'instrument': u'EUR_USD', u'bid': 1.16272, u'time': u'2015-01-19T15:28:52.493297Z' u'tick': u'ask': 1.16283, u'instrument': u'EUR_USD', u'bid': 1.16272, u'time': u'2015-01-19T15:29:12.854066Z' Executing order! "instrument" : "EUR_USD", "time" : "2015-01-19T15:29:14.000000Z", "price" : 1.16283, "tradeOpened" : "id" : 821102691, "units" : 10000, "side" : "buy", "takeProfit" : 0, "stopLoss" : 0, "trailingStop" : 0 , "tradesClosed" : [], "tradeReduced" : u'tick': u'ask': 1.16284, u'instrument': u'EUR_USD', u'bid': 1.1627, u'time': u'2015-01-19T15:29:17.817401Z' u'tick': u'ask': 1.16283, u'instrument': u'EUR_USD', u'bid': 1.1627, u'time': u'2015-01-19T15:29:17.920900Z'
The earliest five principle indicate the JSON tick facts returned from OANDA in the company of bid/ask prices. Subsequently you can see the Executing order!
production as well as the JSON answer returned from OANDA confirming the early on a purchase trade for 10,000 units on EUR/USD and the cost it was achieved at.
This will remain running indefinitely until you slay the program in the company of a "Ctrl-Z" command or similar.
What's Next?
In after articles we are accepted to take out some much-needed improvements, including:
- Real strategies - Proper forex strategies that generate profitable signals.
- Production infrastructure - Remote server carrying out and 24/7 monitored trading system, in the company of stop/start capability.
- Portfolio and risk control - Portfolio and risk overlays for everything suggested orders from the strategy.
- Multiple strategies - Constructing a portfolio on strategies that integrate into the risk control overlay
As in the company of the equities event-driven backtester, we also need to cause a forex backtesting module. That will let us take out rapid research and produce it easier to deploy strategies.
Full Code
settings.py
(remember to change ACCOUNT_ID
and ACCESS_TOKEN
!):
ENVIRONMENTS = "streaming": "real": "stream-fxtrade.oanda.com", "practice": "stream-fxpractice.oanda.com", "sandbox": "stream-sandbox.oanda.com" , "api": "real": "api-fxtrade.oanda.com", "practice": "api-fxpractice.oanda.com", "sandbox": "api-sandbox.oanda.com" DOMAIN = "practice" STREAM_DOMAIN = ENVIRONMENTS["streaming"][DOMAIN] API_DOMAIN = ENVIRONMENTS["api"][DOMAIN] ACCESS_TOKEN = 'abcdef0123456abcdef0123456-abcdef0123456abcdef0123456' ACCOUNT_ID = '12345678'
event.py
:
class Event(object): pass class TickEvent(Event): def __init__(self, instrument, time, bid, ask): self.type = 'TICK' self.instrument = instrument self.time = time self.bid = bid self.ask = ask class OrderEvent(Event): def __init__(self, instrument, units, order_type, side): self.type = 'ORDER' self.instrument = instrument self.units = units self.order_type = order_type self.side = side
streaming.py
:
import requests import json from incident buy in TickEvent class StreamingForexPrices(object): def __init__( self, domain, access_token, account_id, instruments, events_queue ): self.domain = domain self.access_token = access_token self.account_id = account_id self.instruments = instruments self.events_queue = events_queue def connect_to_stream(self): try: s = requests.Session() url = "https://" + self.domain + "/v1/prices" headers = 'Authorization' : 'Bearer ' + self.access_token params = 'instruments' : self.instruments, 'accountId' : self.account_id req = requests.Request('GET', url, headers=headers, params=params) pre = req.prepare() resp = s.send(pre, stream=True, verify=False) go back resp apart from Exception as e: s.close() publish "Caught departure when connecting to stream\n" + str(e) def stream_to_queue(self): answer = self.connect_to_stream() if response.status_code != 200: return for mark in response.iter_lines(1): if line: try: msg = json.loads(line) apart from Exception as e: publish "Caught departure when converting message into json\n" + str(e) return if msg.has_key("instrument") or msg.has_key("tick"): publish msg instrument = msg["tick"]["instrument"] while = msg["tick"]["time"] bid = msg["tick"]["bid"] ask = msg["tick"]["ask"] tev = TickEvent(instrument, time, bid, ask) self.events_queue.put(tev)
strategy.py
:
import random from incident buy in OrderEvent class TestRandomStrategy(object): def __init__(self, instrument, units, events): self.instrument = instrument self.units = units self.events = events self.ticks = 0 def calculate_signals(self, event): if event.type == 'TICK': self.ticks += 1 if self.ticks % 5 == 0: margin = random.choice(["buy", "sell"]) instruct = OrderEvent( self.instrument, self.units, "market", side ) self.events.put(order)
execution.py
:
import httplib import urllib class Execution(object): def __init__(self, domain, access_token, account_id): self.domain = domain self.access_token = access_token self.account_id = account_id self.conn = self.obtain_connection() def obtain_connection(self): go back httplib.HTTPSConnection(self.domain) def execute_order(self, event): headers = "Content-Type": "application/x-www-form-urlencoded", "Authorization": "Bearer " + self.access_token params = urllib.urlencode( "instrument" : event.instrument, "units" : event.units, "type" : event.order_type, "side" : event.side ) self.conn.request( "POST", "/v1/accounts/%s/orders" % str(self.account_id), params, headers ) answer = self.conn.getresponse().read() publish response
trading.py
:
import Queue import threading import time from execution buy in Execution from settings buy in STREAM_DOMAIN, API_DOMAIN, ACCESS_TOKEN, ACCOUNT_ID from policy buy in TestRandomStrategy from streaming buy in StreamingForexPrices def trade(events, strategy, execution): """ Carries out an vast during the time that loop that polls the events line and directs every incident to either the policy part on the execution handler. The loop will at that time pause for "heartbeat" seconds and continue. """ during the time that True: try: incident = events.get(False) apart from Queue.Empty: pass else: if incident is not None: if event.type == 'TICK': strategy.calculate_signals(event) elif event.type == 'ORDER': publish "Executing order!" execution.execute_order(event) time.sleep(heartbeat) if __name__ == "__main__": heartbeat = 0.5 # Half a second between polling events = Queue.Queue() # Trade 10000 units on EUR/USD instrument = "EUR_USD" units = 10000 # Create the OANDA fair cost streaming class # making positive to provide authentication commands prices = StreamingForexPrices( STREAM_DOMAIN, ACCESS_TOKEN, ACCOUNT_ID, instrument, events ) # Create the execution handler making positive to # provide authentication commands execution = Execution(API_DOMAIN, ACCESS_TOKEN, ACCOUNT_ID) # Create the strategy/signal generator, fleeting the # instrument, quantity on units and the events queue policy = TestRandomStrategy(instrument, units, events) # Create two unconnected threads: One for the trading loop # and an extra for the fair cost streaming class trade_thread = threading.Thread(target=trade, args=(events, strategy, execution)) price_thread = threading.Thread(target=prices.stream_to_queue, args=[]) # Start both threads trade_thread.start() price_thread.start()
0 Response to "Forex Trading Diary #1 - Automated Forex Trading With The OANDA API Forex Trading Api"
Posting Komentar