Showing posts with label mistakes. Show all posts
Showing posts with label mistakes. Show all posts

Wednesday, December 12, 2018

A list of #mistakes update: you cannot process events in simple sequential order during live trading

NOTE: I'll keep adding more updates like this under the #mistakes label.

This might be pretty trivial and even obvious, but I keep having to remind myself of this as I "rediscover" it in several somewhat similar situations.

During backtesting you can pretend that you always get events one by one in perfect order and process them in sequence as such because you are in control of time here -- but during live trading you will sometimes get a bulk of events in one go and your strategy, order or event handling code will probably need to be aware of this in order to make good decisions.

E.g.:
  1. You are passed a bulk of events.
  2. An earlier event in the bulk informs you about an order update (e.g. partial fill) which you generate a response to.
  3. A later event in the bulk informs you that the position related to that order was closed for whatever reason.
  4. ...based on §3 your response in §2 might not make sense anymore.
You might think that this will not be a problem for you because your system will be fast enough to handle the events before they queue up anyway -- but this is not only about your system, but also about network and exchange/broker lag. I.e. you are not in control of time here!

As I learn more and more about "stream processing", the more multiple full passes of bulks of data seem to make sense. Sequential processing is an oversimplified view of reality --- it is still useful during simulations though.

Monday, August 20, 2018

Creating a trading system: list of mistakes

I'll publish further updates in separate posts under the #mistakes label.

I'll add to this list as I remember and/or encounter things:
  • Not using enough data for backtesting -- and using the data wrong. I.e. overfitting. This is probably the nr. 1 mistake -- and it's not a binary thing either; you have to determine "how overfit is my strategy? probably?" and yes assuming it is always somewhat overfit is the correct way to view this.
  • Thinking 1min data would be "good enough". It's not unless you explicitly architecture your strategies and backtester around certain limitations. You really need tick data for many strategies or else you end up with a lot of uncertainties as to what happened first when things are hectic (and important); e.g. fill vs. stop-loss vs. take-profit.
  • Not basing the system around continuous time series data/events.
  • Using Joda time instead of primitive longs for timestamps. If I need to deal with messy time calculations I'll coerce the long to a Joda time object then back again.
  • Thinking this would be a 6 month project. I've been doing this on and off since 2015(!). This is the 3rd variant or iteration of the project.
  • Using mutable state. Yes, I did this even in Clojure for "performance reasons". Of course mutable state in Clojure is fine if you do it in isolated areas -- but I did not do this. Even if I was using something like C++ or Rust I'd be doing functional programming and stick with immutable, persistent data structures at this point.
  • It's important to keep the call stack shallow. If one consider handling of exchange related events:
    • Have your main loop call the core and basic handling Fn first.
    • Then have the same loop (call site) pass the event to your strategy Fn which can further handle the event in more custom ways if needed.
    • By keeping the call stack shallow like this your dispatching will be trivial and faster (important if your main-loop does backtesting in addition to live trading) -- and it'll also be easier to eyeball what and where things went wrong via stack traces.
  • Avoid overuse of core.async. I'd only use this tool as a stream library I think; not for the "green thread" type stuff. I.e. avoid async/go.

I'll publish further updates in separate posts under the #mistakes label.