From 7481b2d6cc8db9d390f62e2b91da01b7a69f6996 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Tue, 13 Oct 2020 19:40:43 -0400 Subject: [PATCH] Document optimal strategy for project 6 --- manual_strategy/indicators.py | 7 ++-- manual_strategy/manual_strategy.md | 54 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 manual_strategy/manual_strategy.md diff --git a/manual_strategy/indicators.py b/manual_strategy/indicators.py index 1a5e249..b4be5a2 100644 --- a/manual_strategy/indicators.py +++ b/manual_strategy/indicators.py @@ -1,5 +1,6 @@ import pandas as pd import datetime as dt +import matplotlib.pyplot as plt import TheoreticallyOptimalStrategy as tos from util import plot_data, get_data from marketsim.marketsim import compute_portvals @@ -14,7 +15,6 @@ def test_policy(): symbol = "JPM" start_value = 100000 sd = dt.datetime(2008, 1, 1) - # ed = dt.datetime(2008, 1, 30) ed = dt.datetime(2009, 12, 31) orders = tos.testPolicy(symbol=symbol, sd=sd, ed=ed, sv=start_value) @@ -55,8 +55,9 @@ def test_policy(): portvals["Bench"] = bench["Portval"] portvals.drop(columns=["Portval"], inplace=True) - #XXX: Save to file instead. - plot_data(portvals) + ax = portvals.plot(title="Optimal strategy versus 1000 shares of JPM") + plt.savefig('figure_5.png') + def normalize(timeseries): return timeseries / timeseries.iloc[0] diff --git a/manual_strategy/manual_strategy.md b/manual_strategy/manual_strategy.md new file mode 100644 index 0000000..eedc259 --- /dev/null +++ b/manual_strategy/manual_strategy.md @@ -0,0 +1,54 @@ +# Indicators + + + + +# Optimal Strategy + +The optimal strategy works by applying every possible buy/sell action to the +current positions. A position is cash value, the current amount of shares, and +previous transactions. + +The algorithm then starts with a single initial position with the initial cash +amount, no shares, and no transactions. The algorithm first executes all +possible trades (sell 2000, sell 1000, do nothing, buy 1000, buy 2000). Next, it +filters the invalid holdings, i.e., the other ones where shares are not equal to +-1000, 0, or 1000. Finally, the algorithm keeps the highest cash value for each +amount of shares. + +That is the critical insight that makes the algorithm work. Since the same +amount of shares has the same future potential for creating cash, the only +differentiating factor is the current cash value. Accordingly, for each day, the +algorithm ends up with three new positions. The algorithm could drop the +position with zero shares because buying and selling 2000 shares leverages +future price movements optimally. + +After each trading day, the positions have the same value. I did not expect +that, but it makes sense because the algorithm only keeps the best position from +the previous day. In other words, we can simplify the algorithm by selecting the +best position and then compute the two different positions. Since we already +established that holding zero shares does not make sense, the only two +possibilities are buying or selling 2000 depending on the current amount of +shares. + +![Optimal strategy versus holding 1000 shares](figure_5.png) + +``` +Date Range: 2008-01-02 00:00:00 to 2009-12-31 00:00:00 + +Sharpe Ratio of Optimal Strategy: 13.322769848217233 +Sharpe Ratio of bench: 0.1569184064240322 + +Cumulative Return of Optimal Strategy: 5.7861 +Cumulative Return of bench: 0.012299999999999978 + +Standard Deviation of Optimal Strategy: 0.004547823197907996 +Standard Deviation of bench: 0.01700436627121376 + +Average Daily Return of Optimal Strategy: 0.0038167861508578214 +Average Daily Return of bench: 0.00016808697819094233 + +Final Portfolio Value Optimal: 678610.0 +Final Portfolio Value Bench: 101230.0 +``` +