Combining Mean Reversion and Momentum in the Foreign Exchange Markets

I have just finished a multi-factor model strategy that combines mean-reversion and momentum effects. Please look into Tutorial page for the details. This strategy trade on Forex and rebalance monthly. It's interesting to see how the multi-factor model works on FX markets. You can also add more Forex pairs or change the parameters to explore it.

Any thought, suggestions, discussions on the implementation are welcome and much appreciated!

Update Backtest

Could you please to elaborate more on the relational nexus between the specific model used to predict the returns and the UIP theory rejection? Everything else is clear to me, at least until now


Hey Andrestone:
Thank you for your question. The usage of the UIP theory rejection is to demonstrate that mean-reversion and momentum phenomena exist in FX market. The author used the cumulative deviations from UIP for every currency over previous 6 months to rank the currencies. The currency with the highest cumulative return classifies as the ‘winner’ and the one with the lowest return is the ‘loser’. On the paper we can see obvious momentum and reversion patterns from the winer and the loser(on page 4, figure 1 of the paper).

In a word, the author mentioned UIP for the purpose of demonstrating that mean-reversion and momentum phenomena indeed exist and of supporting the model theoratically.

Thank you for your good question. If this was not clear enough, please feel free to request for more details.


Thanks for your answer! But, just for me to try to get this right, let me try one more time. If I understood correctly, the algorithm basically gets historical data to calculate historical-representative values for mean reversion and momentum, and, after that, merges these values with the ones in the last 3 months and parse them in a formula (based on a model) to calculate the expected returns. My question: Is this formula is a logical derivation from the UIP or it is just a representation of the mean-reversion and momentum phenomena that the author understands as a consequence of the UIP but could be caused by anything else?

Thank you so much!


I copied to notebook and ran it just as is and get this error when doing the backtest.

Want to start off with a backtest before working on tweaking it.

Failed to initialize algorithm: Initialize(): Python.Runtime.PythonException: InvalidCastException : cannot convert object to target type
at Python.Runtime.PyObject.AsManagedObject (System.Type t) [0x00011] in <69d4fd635645431aa1e955e701040fd1>:0
at QuantConnect.Algorithm.QCAlgorithm.GetSymbolsFromPyObject (Python.Runtime.PyObject pyObject) [0x00048] in <116cdc081d27411fa228fed64bb70d2a>:0
at QuantConnect.Algorithm.QCAlgorithm.History (Python.Runtime.PyObject tickers, System.Int32 periods, System.Nullable`1[T] resolution) [0x00001] in <116cdc081d27411fa228fed64bb70d2a>:0
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in :0
at Python.Runtime.PyObject.Invoke (Python.Runtime.PyTuple args, Python.Runtime.PyDict kw) [0x00033] in <69d4fd635645431aa1e955e701040fd1>:0
at Python.Runtime.PyObject.InvokeMethod (System.String name, Python.Runtime.PyTuple args, Python.Runtime.PyDict kw) [0x00007] in <69d4fd635645431aa1e955e701040fd1>:0
at Python.Runtime.PyObject.TryInvokeMember (System.Dynamic.InvokeMemberBinder binder, System.Object[] args, System.Object& result) [0x0003e] in <69d4fd635645431aa1e955e701040fd1>:0
at (wrapper dynamic-method) System.Object:CallSite.Target (System.Runtime.CompilerServices.Closure,System.Runtime.CompilerServices.CallSite,object)
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid1[T0] (System.Runtime.CompilerServices.CallSite site, T0 arg0) [0x0011d] in <63992662b765477a898ef49cdcc99ee2>:0
at QuantConnect.AlgorithmFactory.Python.Wrappers.AlgorithmPythonWrapper.Initialize () [0x00045] in <4ccae4aa57f04451bebbca50379a76cd>:0
at QuantConnect.Lean.Engine.Setup.BacktestingSetupHandler+<>c__DisplayClass19_0.b__0 () [0x00066] in <149201027745430ba9d7e32be5c4266e>:0

me too, got the error responsed.


 Hi Deon Stobe , the updated algorithm is attached in this tutorial

There is a bug in the original algorithm "cannot reindex from a duplicate axis". It happens in get_history() function. As the history request already returns a python dataframe indexed by timestamp date. If you are going to set a new index, try reset the index and then assign the new index to the dataframe.

This is updated algorithm with the bug fixed 


Update Backtest


The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


This discussion is closed