Algorithmic Trading & Portfolio Optimization
A backtest is a claim about a market that does not exist.
- Python
- pandas
- SciPy
- CCXT
Problem
In the market a backtest assumes there is no commission, position sizes divide infinitely, buying and selling happen at one price, depth at that price is unlimited, and the analyst knew in advance which parameters would work.
None of these hold. The question is which of them costs how much.
Solution
Cross-sectional momentum on ten liquid crypto pairs, three years of daily bars, 250,000 USDT, a 45-point parameter grid. The assumptions are removed one at a time, with the best result re-reported at every rung: real commission, tick and lot rounding, spread, finite depth, and finally walk-forward.
The Markowitz claim is tested against a control too: tangency portfolio, minimum variance, equal weight, and a hold the least volatile single asset control.
Outcome
The frictionless backtest gives Sharpe 1.90 and 165.1% a year. After walk-forward it is Sharpe 0.70 and 26.0% a year: 15.7% of the backtested annual return survives.
The ordering is not the expected one. Retail discussion is about commission and slippage; commission costs 7 points and slippage 0.4. What kills the strategy is depth (−70 points) and your own parameter search (−61.7 points). All eight folds chose different parameters; folds scoring 1.18-2.42 in training scatter between +3.26 and −1.93 out of sample.
On the Markowitz side, minimum variance beats tangency out of sample (1.57 against 1.41) and loses less than half as much. But both optimisers put 73-83% of the weight in gold; the added control reproduces 60% of the difference.
The Corwin-Schultz estimator (Journal of Finance, 2012) infers the spread from the daily high-low range. On BTC/USDT it reports 75 basis points; the order book reports 0.002. A factor of 48,398.
The estimator is not broken. It was derived for equities, where the range is meaningfully made of spread. On a liquid crypto pair the range is volatility, end to end.
Had it been used, what got reported as "spread cost" would have been volatility, and the headline finding would have been an artefact, one that would have survived any review because the code is correct. The only reason it was caught is that the order book was measured separately.
Source code
Comments are shown in the page language. Files in the repository carry both English and Turkish.
Project structure
README.md
112 lines · 9 KB
Loading…