In today's entry of the Forex Trading Diary I want to discuss the longer term plan for the forex trading system. In addition I want to outline how I've used Python's Decimal data-type to make calculations more accurate.
To date, we've been experimenting with the OANDA Rest API in order to see how it compared to the API provided by Interactive Brokers. We've also seen how to add in a basic portfolio replication element as the first step towards a proper event-driven backtesting system. I've also had some helpful comments on both previous articles (#1 and #2), which suggests that many of you are keen on changing and extending the code yourselves.
For the reasons outlined above I have decided to open-source the forex trading system. What does this mean? It means that all current and future code will be available for free, under a liberal MIT open source license, on the Github version control website at the following URL: https://github.com/mhallsmoore/qsforex.
For those of you who have used git and Github before, you'll be able to
git clone the repo and start modifying it for your own purposes.
The QuantStart Automated Forex Trading System is now open-source under a liberal MIT license. You can find the latest code on Github under the qsforex repository at https://github.com/mhallsmoore/qsforex.
For those of you who are new to source version control you will probably want to read up on how git (and version control in general) works with the fantastic free ebook Pro Git. It is worth spending some time learning about source control as it will save you a huge amount of future headache if you spend a lot of time programming and updating projects!
The "quick start" for a Ubuntu system is to install git:
sudo apt-get install git-core
You will then need to make a directory for the qsforex project to live in and "clone" the project from the Github site as follows:
mkdir -p ~/projects/ cd ~/projects/ git clone https://github.com/mhallsmoore/qsforex.git
At this point you will need to create a virtual environment in which to run the code:
mkdir -p ~/venv/qsforex cd ~/venv/qsforex virtualenv . source ~/venv/qsforex/bin/activate
You will then need to install the requirements (this will take some time!):
pip install -r ~/projects/qsforex/requirements.txt
Finally you will need to create a symbolic link in your Python virtual environment to allow you to type
import qsforex in your code (and run it!):
ln -s ~/projects/qsforex/ ~/venv/qsforex/lib/python2.7/site-packages/qsforex
As I mentioned in the previous entries you will need to create the necessary environment variables for your OANDA authentication credentials. Please see diary entry #2 for instructions on how to do this.
Please pay attention to the README associated with the repo, as it contains installation instructions, a disclaimer and a warranty about using the code.
Since the software is in "alpha" mode, these instructions will become more straightforward as time progresses. In particular I will try to wrap the project into a Python package so that it can be easily installed via pip.
If you have any questions about the installation procedure, then please don't hesitate to email me on email@example.com.
The "philosophy" of the forex trading system, as with the rest of the QuantStart site, is to try and mimic real-life trading as much as possible in our backtesting. This means including the details that are often excluded from more "research oriented" backtesting situations. Latency, server outages, automation, monitoring, realistic transaction costs will all be included within the models to give us a good idea of how well a strategy is likely to perform.
Since we will have access to tick data (bid/ask timestamps) we will be able to incorporate the spread into the transaction costs. We can also model slippage. It is less straighforward to model market impact, although this is less of a concern at smaller trading amounts.
In addition to transaction costs we want to model robust portfolio management using risk overlays and position sizing.
So what is currently included in the Forex Trading System to date?
Strategyobject, which creates
Portfolioto OANDA. By "blindly" I mean that there is no risk management or position sizing being carried out, nor any algorithmic execution that might lead to reduced transaction costs.
Portfolioobjects with. Handling multiple currency pairs is an important next step. This will involve modification to the position and portfolio calculations.
Positionobjects. Since these are so crucial to the calculations of the strategy, one must be extremely confident that they perform as expected. An additional benefit of such tests is that they allow the underlying calculation to be modified, such that if all tests still pass, we can be confident that the overall system will continue to behave as expected.
At this stage the Forex Trading System is lacking the following functionality:
Portfolioobject to allow us to perform realistic backtesting. At this stage we are missing a historical tick data storage system. In subsequent articles we will look at obtaining historical tick data and storing it in an appropriate database, such as HDF5.
As can be seen there is a lot of functionality left on the roadmap! That being said, each new diary entry (and potential contributions from the community!) will move the project forward.
Now that we have discussed the longer term plan I want to present some of the changes I have made to the code since diary entry #2. In particular, I want to describe how I modified the code to handle the Decimal data-type instead of using floating point storage. This is an extremely important change as floating point representations are a substantial source of long-term error in portfolio and order management systems.
Python natively supports decimal representations to an arbitrary precision. The functionality is contained within the decimal library.
In particular we need to modify -every- value that appears in a
Position calculation to a
Decimal data-type. This includes the units, exposure, pips, profit and percentage profit. This ensures we are in full control of how rounding issues are handled when dealing with currency representations that have two decimal places of precision. In particular we need to choose the method of rounding. Python supports a few different types, but we are going to go with
ROUND_HALF_DOWN, which rounds to the nearest integer with ties going towards zero.
Here is an example of how the code is modified to handle
Decimal data-types from their previous floating point representations. The following is a list of
from decimal import Decimal, getcontext, ROUND_HALF_DOWN class Position(object): def __init__( self, side, market, units, exposure, avg_price, cur_price ): self.side = side self.market = market self.units = units self.exposure = Decimal(str(exposure)) self.avg_price = Decimal(str(avg_price)) self.cur_price = Decimal(str(cur_price)) self.profit_base = self.calculate_profit_base(self.exposure) self.profit_perc = self.calculate_profit_perc(self.exposure) def calculate_pips(self): getcontext.prec = 6 mult = Decimal("1") if self.side == "SHORT": mult = Decimal("-1") return (mult * (self.cur_price - self.avg_price)).quantize( Decimal("0.00001"), ROUND_HALF_DOWN ) def calculate_profit_base(self, exposure): pips = self.calculate_pips() return (pips * exposure / self.cur_price).quantize( Decimal("0.00001"), ROUND_HALF_DOWN ) def calculate_profit_perc(self, exposure): return (self.profit_base / exposure * Decimal("100.00")).quantize( Decimal("0.00001"), ROUND_HALF_DOWN ) def update_position_price(self, cur_price, exposure): self.cur_price = cur_price self.profit_base = self.calculate_profit_base(exposure) self.profit_perc = self.calculate_profit_perc(exposure)
Note that we must provide
Decimal with a string argument, rather than a floating point argument. This is because a string is precisely specifying the precision of the value, whereas a floating point type will not.
Note also that when we begin storing our trades in a relational database (as described above in the roadmap) we will need to make sure we once again use the correct data-type. PostgreSQL and MySQL support a decimal representation. It is vital that we utilise these data-types when we create our database schema, otherwise we will run into rounding errors that are extremely difficult to diagnose!
For those who are interested in a deeper discussion of these issues, in mathematics and computer science, the subject of Numerical Analysis covers floating point storage issues, among many other interesting topics.
In subsequent diary entries we are going to discuss how I have applied unit testing to the code and how we can extend the software to more currency pairs by modifying the position calculations.
If you would like to read the other entries in the series, please follow the links below:comments powered by Disqus