Friday, 18 December 2015

pysystemtrade

There are already many python packages where you can back test trading strategies. Some of them also include a framework for automatic execution and complete position management.

I can't give an exhaustive list but I'll pick out:

- Quantopian's  zipline
- BT
- pythalesians
- pyalgotrade

There is a longer list here

Does the world really need another one? Well, probably not, but today I've released one anyway (this explains at least partly why it's been a month since my last post, since I've spent the last month writing it).

You can find pysystemtrade on github, here. This is version 0.0.1. It provides a basic backtesting enviroment that implements the 'staunch systems trader' example in my book. And it's GPL 3 open source.

However it's my intention that this will become a fully featured back tester that will include all the optimisation and calibration techniques that I've discussed here on the blog, and in my book. It will also, eventually, include a complete end to end system that can be used for fully automated futures trading with interactive brokers.


Why am I doing this?


Having said that this is probably a futile exercise, it's probably worth explaining why I've released this today.


My own code needs rewriting


I've been running with a trading system that I wrote in early 2014 for the best part of 21 months. Whilst it's been pretty stable, it isn't very pretty or extendable.  There are things I'd like to do with my system that I can't implement without having to do a massive refactoring; massive enough that a rewrite from the ground up would be better. Parts of it are over engineered; other parts too tightly coupled. I'd probably make different decisions about many parts of it with the experience I've had. I'd also like to move to python 3.

Oh yes pysystemtrade is in python 3; well 3.4. Didn't I mention that? Sorry...

So the job of rewriting this code has been on my back list for some time. Doing it in public will hopefully encourage me to finish the job.


I like to write my own stuff


A question I'm often asked is why I didn't write my original trading system as part of, or as an extension of, one of the libraries I mentioned above. It's equally valid to ask why I'm writing everything from scratch again.

I've worked with quite a few backtesting frameworks in my life. I've never been completely happy with frameworks that someone else has written. Whenever you use someone elses stuff there is an obvious benefit, but three costs. The first cost is the time penalty in understanding how to use the product. The second is the time spent in extending it to do what you want it to do.

Since I already know that 95% of the final code base isn't going to be back testing, but production implementation of a trading system, the benefits of using someone elses backtesting framework are mostly outweighed by these two costs.

Also as a linux user I get irritated when to use someone elses code I have to install a huge stack of python libraries first. That's why there are minimal dependencies for this.

The third cost is that you have to put up with the API that the developer has imposed. In particular I'm very choosy about how I spend my time at the command line developing systems on the fly (in my previous job I spent a lot of time moaning at technologists when they tried to create a trading system that was lovely and robust, but hard to use interactively. They got it right in the end).

Finally it's just more fun to write your own stuff; if you're a strange person like me.

By the way I know that there are many of you who also like to, and have, written your own stuff. So I'll try and keep the code relatively modular. When I drop my optimisation code into the project, it should be easy to remove it and tie it into your own system. Should you want to use a different broker, or different storage and data feeds, I'll make that as straightforward as I can.

Pro-bono publico

 
I've noticed that writing on this blog has involved writing quite a bit of code (and I keep getting requests to write some more). Whilst the original series of posts I wrote about using swigibpy is quite self contained; subsequently I seem to be putting together quite a little messy pile of code in the systematictradingexamples repo..

Rightly or wrongly I reckon it will be better for all concerned if I created a single project that held all the code I use to demonstrate techniques and points of interest. At some point I'll circle back and rewrite the examples in systematictradingexamples into this new project).

Encouraging people to trade properly is a bit of a mission of mine. If this project helps one person who would otherwise be using some overfitted 'robot' trader tied to an expensive broker, then it will be worth it (though I'd hope for a better return on my time).


Sorry - no support


I had one big concern about releasing my code open source. Not that I would give away any deep secrets; as you will know if you've been paying attention I don't believe in secret sauce.

I also have the natural embaressment of showing people my code, especially given I am not by any means a professional programmer. So be nice, or I'll pull it all from the repo :-)

No I was concerned, based on my experience with the code I've already released, that answering emails of the 'this doesn't work' type will eventually take all my time. For this reason I've decided (a) this project will be thoroughly documented and will have some tests, and (b) I won't be committing to to help you with any problems. Here's what I say in the README file:

"This is an open source project, designed for people who are already comfortable using and writing python code, are capable of installing the dependencies, and who want a head start on implementing a system of their own. I do not have the time to provide support. Of course I am very happy if you get in touch with me on any of the following topics:

  • Confusing error messages
  • Missing or misleading documentation
  • Suggestions for extra features
However I can't guarantee that I will reply immediately, or at all. If you need that level of support then you are better off with another project.
I'll try and incorporate any feedback into the code, but this is a part time venture for me, and it will be competing with my other interests (writing books, blogging and research). But if you occasionally check github you will hopefully find it gradually improving. Offers to contribute will of course be gratefully accepted."

Look guys let me make it clear. You're getting the benefit of my distilled wisdom for free (though some of you have shelled out up to $60 for my book, for which I thank you from the bottom of my heart); something my former employer used to pay quite a lot of money for. But becoming an unpaid technical support monkey for a bunch of strangers (and a few old friends and colleague) on the internet isn't my idea of fun. I'll make an effort to release stable code, write a few tests, and document it properly, but then you're on your own.

Also this is open source. I know for a fact that at least half the people reading this blog are better programmers than I. If you find a bug or want to improve the code in some way, then please feel free to offer to do it (and thanks to those of you who have offered, or have already done so).


A very quick demo


There is a long demo, and an even longer user guide, in the repo so I don't need to repeat them here. Instead here is how you'd simulate the system in chapter 15 of my book, in three lines:


from systems.provided.futures_chapter15.basesystem import futures_system
from matplotlib.pyplot import show

system = futures_system()

system.accounts.portfolio().sharpe()
system.accounts.portfolio().curve().plot()
show()


The account curve for the system in chapter 15 of my book. Sharpe Ratio 0.48

Seasons greetings to one and all


This will be my last post for the year. I hit a high water mark in my trading account yesterday so I'm in a good mood. So please feel free to enjoy the warm feelings I am currently transmitting into this keyboard, have a good holiday, and see you next year.


40 comments:

  1. ive been backtesting in vba and amibroker for a long time and i agree with you that being able to fully customize the framework is a must when backtesting and fully automating trading systems.

    thank you very much for your py framework, ill be getting a copy of your book asap (international shipping is slow).

    ReplyDelete
  2. I'll second Eduardo. I just bought your book, downloaded Python coincidentally a few days ago, and will try out pysystemtrade. I to come from an Amibroker bg. Not sure what I'm going to *do* learning Python, but I'll get to that point when I get to it.

    ReplyDelete
  3. Very interesting development, hope you can find time to finish this project. I am not a professional programmer but i'd be glad to contribute. On the same topic, Quantstarts in his blog is planing to release a series of articles about system development from scratch https://www.quantstart.com/articles/Announcing-the-QuantStart-Advanced-Trading-Infrastructure-Article-Series

    ReplyDelete
    Replies
    1. Max,

      I hadn't realised Mike was doing that. Very interesting (and a little spooky - great minds think alike...). I have a lot of respect for the stuff Mike does, as like me he places a lot of emphasis on how you do stuff being more important than what you do. He's also a little different to me; he's a very decent programmer and comes more from a 'quant' background, whereas programming is definitely my weaker skill set and I couldn't explain Ito's lemma with a gun to my head (it's not that I've forgotten, even when I was paid to trade options I didn't get it...). Also he focuses more on event driven faster trading in equities, whereas I'm more interested in end of day vector backtests in futures. Nevertheless I'd recommend people keep an eye on both projects as there's bound to be some advantage in getting both of these perspectives (To avoid subconcious plagarism I'm going to avoid looking at Mike's page until I've finished developing this project... so might be at least a year or so!).

      Delete
  4. Thank you very much for sharing this. Indeed, custom solution has serious benefits. Just wanted to say that I found very helpful the user guide you mentioned in the post. A quick link for other readers to jump to the guide: https://github.com/robcarver17/pysystemtrade/blob/master/docs/userguide.md

    Happy holidays!

    ReplyDelete
  5. Dear Rob, this is great news! Thanks! However, I'm not a python geek whatsoever is there a version of this framework within excel? Or maybe you know a way to convert it to c# code?

    Also, after reading the entire book, i have the following misunderstanding:

    Why when adjusting returns of the rule by volatility we use daily returns of an asset, rather than volaility of the rule or strategy itself?

    Different rules could trade 10 times a year or 10 000 times a year would i still standardize them the same way - by dividing by daily annualized volatility of returns of an asset?

    What if I trade EWMAC rule on 30 MIN TF, would i still use daily returns of an asset to standardize its returns?

    Looking forward to your response, as I'm more confused now than ever =).




    ReplyDelete
    Replies
    1. Hi P_Ser,
      You can find snippets of excel pointed to from here http://www.systematictrading.org/info. At some point I will publish a post explaining in more detail how you'd use excel to run a strategy. I know of at least one person who has managed to implement my framework in excel, so it's possible.

      I'm afraid I don't know any C##. However if you're proficient in C## you should find Python a breeze.

      In response to your second question I assume you're talking about something like the denominator: ewmac = (ewma_fast - ewma_ slow) / vol(asset_returns)


      The reason we do this is to get a forecast that is not in any units. The numerator is in price differences (price - another price). So if we divide by vol(returns) which is also in price difference units, we remove the units completely from the forecast.

      This would be true no matter how often the thing traded.

      Clearly this wouldn't be necessary for all types of forecasts. If you have a forecast that is already scale free you wouldn't need to do this. But for the ones I use, which are all technical trading rules using price, it's always neccessary.

      Once you've got a scale free forecast, then you need to normalise it so it's on the correct scale (mean absolute value of 10). At this point you'd look at the standard deviation of the forecast to get the right normalisation forecast.

      Ps if you liked my book then please review it on Amazon

      Delete
    2. Robert, thanks for the prompt response! I gladly wrote a review on Amazon

      Delete
  6. Hi Rob,
    Firstly thank you so much for your articles!
    They are so informative and practical.
    I was wondering if you could do an article on the carry trade/ co integration strategy (hedged strategy) as I am looking at writing a thesis on it.
    Many thanks and best,
    Andrew

    ReplyDelete
  7. Hi Rob,

    I don’t know if this is the right place to ask this question or should I post it as issue on github.

    I looked over the code and I notice that when you load the data you resample it for business days which means that if a business day is missing it will add it and fill it with NaN.

    My question is: what’s the benefit of doing that instead of just keep those missing days out of the time series?

    ReplyDelete
    Replies
    1. It means that code which assumes a certain frequency will work. For example consider a 10 day moving average (2 calendar weeks). With a missing day I don't want to use an 11 day moving average; I want to average 10 days including the nan. Some panda methods will not be affected by this but I prefer to be safe.

      Delete
  8. Hi Rob,
    This is my favourite blog on the web. Great work!
    When you run your Python code, what do you use and what would you recommend to use? I suspect you may be using BASH as a Linux user? I am Windows based - is there anything you'd recommend for a Windows user? The Python shell?
    Thank you

    ReplyDelete
    Replies
    1. Yes linux mint / bash. I am afraid I don't use windows at all so I'm clueless. Try tweeting @thalesians he is a windows / python guy.

      Delete
  9. Hi Rob,
    I cannot see in pysystemtrade where futures specific information is located, such as e.g., multipliers on futures. This of course significantly affects the PnL. Can you comment on this - where can I find it and if this is not accounted for, what's the reasoning behind that?
    Thanks!

    ReplyDelete
    Replies
    1. https://github.com/robcarver17/pysystemtrade/blob/master/sysdata/csvdata.py

      eg line 247
      system.data.get_value_of_block_price_move("EDOLLAR")

      Delete
    2. Hi Rob,
      I am trying to understand your backtesting system.
      One thing I am trying to get my head around is how you test your whole system over different dates. I am expecting something like methods being applied to a pandas DataFrame of price time series, or 'for each date, apply this rule'. Where can I see the information drawn from the data as at specific dates / where can I look to understand this in your code?
      Thank you!

      Delete
    3. Mostly this is done as a vectorised operation not date by date eg https://github.com/robcarver17/pysystemtrade/blob/master/systems/provided/futures_chapter15/rules.py line 9 onwards shows how the EWMAC rule is applied.

      Delete
  10. Hi Rob,
    Can you explain what is meant by 'buffered position' and 'buffers' for positions in pysystemtrade?
    Thanks

    ReplyDelete
    Replies
    1. https://github.com/robcarver17/pysystemtrade/blob/master/docs/userguide.md#buffering-and-position-intertia

      and/or Chapter 11 of my book

      Delete
  11. Hi Rob,
    How often do you update your instrument weights? Every day, annually, quarterly?
    Will you be including your breakout system in pysystemtrade?

    ReplyDelete
    Replies
    1. I only update my instrument weights when the set of instruments I have changes. There have been a few changes for various reasons, but if there are no more I don't plan to update my instrument weights again.

      Yes, the breakout system will be included.

      Delete
  12. Hi Rob,
    When utilising the command "system.accounts.portfolio().curve().plot()", is there a way of restricting the x-axis to show only particular periods? E.g., 2010-2015?

    ReplyDelete
  13. system.accounts.portfolio().curve() is just a pandas data frame. So the normal indexing functions should work.

    ReplyDelete
  14. Hi Rob, In pysytemtrade I find the "system.portfolio.get_instrument_weights()" function useful, particularly with plotting to get an idea of dynamic instrument weighting over time (e.g., as new instruments enter).

    Is there also a way to examine the weights assigned to trading rules over time? Something like "system.portfolio.get_RULE_weights()". I have been through the documentation and user guide, but could not find this feature.

    Also, is there a way to set an upper bound for the instrument weights, so that no instrument may take on a weight larger than e.g., 10%?

    ReplyDelete
    Replies
    1. system.combForecast.get_forecast_weights(instrument_code)

      mentioned here https://github.com/robcarver17/pysystemtrade/blob/master/docs/userguide.md#table-of-standard-systemdata-and-systemstage-methods

      Constraints
      https://github.com/robcarver17/pysystemtrade/blob/master/syscore/optimisation.py

      line 601
      bounds=[(0.0,1.0)]*number_assets

      Change to bounds=[(0.0,0.1)]*number_assets

      Note if there aren't at least 10 assets this will clearly fail so you probably need to write some code to cope with this corner case. I'd obviously advise not hard coding 0.1 and passing this in through parameters.

      Delete
    2. Thanks for this. This gets me the weights for each trading rule for a given instrument. I understand the weights for trading rules vary for each instrument. Is there a straight-forward way to obtain the aggregate average weights assigned to each trading rule within the whole portfolio?

      Also, I am reviewing the CSVs to get an idea of the rolling frequencies for each instrument. I note that these change from time to time. E.g., the rolling convention for COPPER seems to have changed recently - it shifted e.g., from Feb/ May to Mar/Apr in the more recent history. Is there a logic you've applied to the frequency for the historical data (I have read your post on futures rolling)? This also happens for e.g., EDOLLAR, but I understand this is because of the dangerously low vol and sudden bursts of vol at the front end of ED contracts due to CB intervention.

      Delete
    3. Additionally, is there a reason why for some agricultural commodities (e.g., CORN, CRUDE_W) the carry contract is in front of the price contract, whereas for most of the assets the carry contract is further out than the price contract (the latter makes more sense to me)?

      Delete
    4. "Additionally, is there a reason why for some agricultural commodities (e.g., CORN, CRUDE_W) the carry contract is in front of the price contract, whereas for most of the assets the carry contract is further out than the price contract (the latter makes more sense to me)?"

      Read Appendix B of the my book or http://qoppac.blogspot.co.uk/2015/05/systems-building-futures-rolling.html. Carry should be in front of spot, as it is for Crude (as the contract ages ). That isn't possible for eg. equity and bond indices, so I use the further out contract.

      Delete
    5. "Is there a straight-forward way to obtain the aggregate average weights assigned to each trading rule within the whole portfolio?"

      Not yet (you'd have to get the weights for each instrument, multiply by instrument weight and sum up across forecast rules). Mind you the code defaults to estimating the same forecast weights for everything anyway.

      Delete
    6. " Is there a logic you've applied to the frequency for the historical data (I have read your post on futures rolling)"

      The last 2 years are the dates when I personally chose to do the roll. Before that is generated by a simple rule, with manual adjustments.

      In some cases the historical volume pattern has changed. For Copper the volume pattern is quite noisy. I may also choose to roll at different times. This could come down to something like having no position and being about to go on holiday...

      Delete
    7. This makes sense. Thank you as always

      Delete
  15. Hi Rob, I notice in your most recent update to the User Guide, the Post Processing section in Optimisation has switched formatting between text and formulas, so the formulas are treated as text and vice-versa, making it a little difficult to interpret.

    ReplyDelete
  16. Hi,
    I note you had previously mentioned that you maintain a short bias to the VIX, so that the forecast equals -10 for a rule applied ONLY to VIX/V2X, and that this is approx. 10% of your portfolio. I have questions on two themes:
    1) How can I apply a rule to only one or two instruments (VIX, V2X) in pysystemtrade, and exclude all other instruments from this rule?
    2) What is the 10%? Is that the rule weight applied only to VIX and V2X, so that they are subject to all other rules (e.g., ewmac, carry) but with an additional fixed 10% allocation to a rule with a fixed forecast of -10? Does the weight on this rule change over time due to optimisation or is it fixed?

    ReplyDelete
    Replies
    1. 1)

      With fixed weights config.forecast_weights=dict(EDOLLAR=dict(ewmac8=0.9, ewmac16=0.1), V2X=longonly=.5, ewmac16=.5))

      Estimated weights:
      system.config.rule_variations=dict(EDOLLAR=["ewmac8","ewmac16"], V2X=["longonly", "ewmac16"])

      2) No you have to increase the amount on V2X, VIX. Suppose you had 10 markets, including VIX. You want 90% in trend following, 10% in long only. This is another way of handcrafting where you work at the whole portfolio level. So you split 90% into ten markets, 9% in each, including VIX. 10% goes into VIX. VIX then has 19%, other 9 markets 81%. VIX is 10/19 carry, 9/19 VIX. Other markets 100% trend.

      These are my handcrafted weights used in my live system. But I'd run a backtest with a proper optimisation to check they aren't overfitted, or way off.

      Delete
    2. Thank you. Is the short vol rule vol-adjusted or is it equivalent to a constant forecast of -10 for the rule regardless of price movements?

      Delete
    3. It's -10 regardless (so the position is vol adjusted in the normal way, but the forecast is constant)

      Delete
    4. Hi Rob,
      I see you have added 'long only' to the rule set in additional rules section (with breakout).
      I cannot figure out how to get it to work.
      I include 'long only' in my rules and in my config, but continually run into problems.
      Would you be able to include an example of how to use 'longonly' in pysystemtrade?

      Delete
    5. I haven't finished adding the rule, otherwise it would have appeared in the release notes. There is some extra code that needs to be written. I'm afraid you will have to wait.

      Delete
  17. This comment has been removed by the author.

    ReplyDelete