Robust Portfolio Optimization
Robust Return as Risk Constraint
using HiGHS
using Clarabel
using Distributions
using PortfolioOpt
using PortfolioOpt.TestUtils
Read Prices
prices = get_test_data();
numD, numA = size(prices) # A: Assets D: Days
(316, 6)
Calculating returns
returns_series = percentchange(prices);
315×6 TimeSeries.TimeArray{Float64, 2, Dates.Date, Matrix{Float64}} 2009-09-02 to 2010-12-01
┌────────────┬──────────────┬──────────────┬─────────────┬─────────────┬────────
│ │ AAPL │ BA │ DELL │ CAT │ EBAY ⋯
├────────────┼──────────────┼──────────────┼─────────────┼─────────────┼────────
│ 2009-09-02 │ -0.000725953 │ -0.00758663 │ 0.00920447 │ -0.00752737 │ -0.0 ⋯
│ 2009-09-03 │ 0.00829398 │ 0.00123967 │ -0.00651466 │ 0.0351643 │ 0.00 ⋯
│ 2009-09-04 │ 0.0225758 │ 0.0142385 │ 0.0288525 │ 0.0237567 │ 0.0 ⋯
│ 2009-09-08 │ 0.0153837 │ 0.00712106 │ 0.0172084 │ 0.0186511 │ -0.0 ⋯
│ 2009-09-09 │ -0.010351 │ 0.0208081 │ -0.00250627 │ 0.0306579 │ 0.0 ⋯
│ 2009-09-10 │ 0.0082973 │ -0.000791609 │ 0.040201 │ 0.00578393 │ 0.0 ⋯
│ 2009-09-11 │ -0.00231803 │ 0.0170331 │ 0.00241546 │ -0.0032861 │ 0.00 ⋯
│ 2009-09-14 │ 0.00906134 │ -0.00740019 │ -0.0126506 │ 0.00494539 │ 0.0 ⋯
│ ⋮ │ ⋮ │ ⋮ │ ⋮ │ ⋮ │ ⋱
│ 2010-11-22 │ 0.0216151 │ 0.00691933 │ 0.00431655 │ 0.00035727 │ 0.0 ⋯
│ 2010-11-23 │ -0.0147753 │ -0.0067156 │ -0.0100287 │ -0.0163095 │ -0.0 ⋯
│ 2010-11-24 │ 0.0196612 │ 0.0284591 │ 0.00434153 │ 0.0249304 │ 0.0 ⋯
│ 2010-11-26 │ 0.000635324 │ -0.00932579 │ -0.0165706 │ -0.00661235 │ -0.00 ⋯
│ 2010-11-29 │ 0.00593651 │ -0.00679012 │ -0.00586081 │ -0.00546773 │ -0.0 ⋯
│ 2010-11-30 │ -0.0180516 │ -0.00916718 │ -0.0257922 │ 0.0111151 │ -0.0 ⋯
│ 2010-12-01 │ 0.0168729 │ 0.0305786 │ 0.0143722 │ 0.0336879 │ 0.00 ⋯
└────────────┴──────────────┴──────────────┴─────────────┴─────────────┴────────
2 columns and 300 rows omitted
Backtest parameters
DEFAULT_SOLVER = optimizer_with_attributes(
HiGHS.Optimizer, "presolve" => "on", "time_limit" => 60.0, "log_to_console" => false
)
Clarabel_SOLVER = optimizer_with_attributes(
Clarabel.Optimizer, "verbose" => false, "max_iter" => 900000
)
date_range = timestamp(returns_series)[100:end];
216-element Vector{Dates.Date}:
2010-01-26
2010-01-27
2010-01-28
2010-01-29
2010-02-01
2010-02-02
2010-02-03
2010-02-04
2010-02-05
2010-02-08
⋮
2010-11-18
2010-11-19
2010-11-22
2010-11-23
2010-11-24
2010-11-26
2010-11-29
2010-11-30
2010-12-01
Backtest Soyster's robust return
backtest_results = Dict()
backtest_results["Soyster"], _ = sequential_backtest_market(
VolumeMarketHistory(returns_series), date_range,
) do market, past_returns, ext
numD, numA = size(past_returns)
returns = values(past_returns)
k_back = 30
Σ, r̄ = mean_variance(returns[(end - k_back):end, :])
d = MvNormal(r̄, Σ)
R = -0.015 / market_budget(market)
formulation = PortfolioFormulation(MAX_SENSE,
ObjectiveTerm(ExpectedReturn(d)),
RiskConstraint(ExpectedReturn(BudgetSet(d; Δ=maximum(abs.(returns); dims=1)'[:] .- r̄, Γ=numA * 1.0)), GreaterThan(R)),
)
pointers = change_bids!(market, formulation, DEFAULT_SOLVER)
return pointers
end
(Dict{Symbol, PortfolioOpt.StateRecorder}(:decisions => PortfolioOpt.DecisionRecorder{Float64}(2-dimensional DenseAxisArray{Float64,2,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
Dimension 2, 1:6
And data, a 216×6 Matrix{Float64}:
-0.0 -0.0 -0.0 0.0 -0.0 0.22133782399067825
0.0 -0.0 -0.0 -0.0 -0.0 0.22274374461691798
-0.0 -0.0 -0.0 0.0 -0.0 0.22346785096665636
-0.0 -0.0 -0.0 0.0 -0.0 0.22264233125936214
0.0 -0.0 0.0 0.0 -0.0 0.2130308591611971
-0.0 -0.0 0.0 0.0 -0.0 0.21026542724706543
-0.0 -0.0 0.0 0.0 -0.0 0.21181605677601587
-0.0 -0.0 0.0 0.0 -0.0 0.21732069450387714
0.0 -0.0 0.0 0.0 0.0 0.2040926851602658
0.0 -0.0 0.0 0.0 -0.0 0.2024300359954988
⋮ ⋮
-0.0 0.0 0.0 -0.0 -0.0 0.20601915037031057
-0.0 0.0 -0.0 -0.0 0.1944466634604701 -0.0
-0.0 0.0 -0.0 -0.0 -0.0 0.19850920482854967
-0.0 0.0 -0.0 -0.0 0.1941799010326254 -0.0
-0.0 0.0 -0.0 -0.0 0.19434675809892202 -0.0
-0.0 0.0 -0.0 -0.0 0.198113869042182 -0.0
-0.0 0.0 0.0 -0.0 0.19472377696208812 -0.0
-0.0 0.0 0.0 -0.0 0.1878552264024443 -0.0
0.0 0.0 0.0 -0.0 -0.0 0.1903899042825381), :wealth => PortfolioOpt.WealthRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01"), Dates.Date("2010-12-02")]
And data, a 217-element Vector{Float64}:
1.0
1.0032107027958757
1.0103767213894495
1.0076680201656112
0.996545660058877
1.002048302177432
1.007153667767064
1.011802834948276
1.0009741405485983
0.9982061565726453
⋮
1.0904873347476276
1.0887699451783006
1.087794469970298
1.0848792364691553
1.0915120118449635
1.0911311457077468
1.0853800742854316
1.0786065977131964
1.0848175607136306), :returns => PortfolioOpt.ReturnsRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
And data, a 216-element Vector{Float64}:
0.0032107027958756342
0.007143084272927611
-0.0026808824535400387
-0.011037722627047565
0.0055217160026865535
0.005094929634168496
0.00461614481484187
-0.010702376021936383
-0.002765290194645818
0.0011152730505045718
⋮
-0.006302792592161171
-0.0015748826369675444
-0.0008959424461730876
-0.0026799488153512454
0.006113837515588495
-0.0003489344442236808
-0.005270742609574128
-0.006240649457927837
0.005758320979680924)), nothing)
Backtest Bertsimas's robust return
backtest_results["Bertsimas"], _ = sequential_backtest_market(
VolumeMarketHistory(returns_series), date_range,
) do market, past_returns, ext
numD, numA = size(past_returns)
returns = values(past_returns)
k_back = 30
Σ, r̄ = mean_variance(returns[(end - k_back):end, :])
d = MvNormal(r̄, Σ)
R = -0.015 / market_budget(market)
formulation = PortfolioFormulation(MAX_SENSE,
ObjectiveTerm(ExpectedReturn(d)),
RiskConstraint(ExpectedReturn(BudgetSet(d; Δ=maximum(abs.(returns); dims=1)'[:] .- r̄, Γ=numA * 0.3)), GreaterThan(R)),
)
pointers = change_bids!(market, formulation, DEFAULT_SOLVER)
return pointers
end
(Dict{Symbol, PortfolioOpt.StateRecorder}(:decisions => PortfolioOpt.DecisionRecorder{Float64}(2-dimensional DenseAxisArray{Float64,2,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
Dimension 2, 1:6
And data, a 216×6 Matrix{Float64}:
0.20289308736653008 0.24486952446614163 … 0.12726584082925055
0.1953388446189664 0.24063740619103535 0.12537474874411006
0.1988578503457958 0.13702293602214888 0.1268202707862655
0.19187430733948374 0.13507535643019292 0.12469450606375979
0.0 -0.0 0.2154258801732391
0.18592588582365166 0.1317305186810252 … 0.1189860566133338
0.18584228910267342 0.1323870870545527 0.1195078623397213
0.19412986482017278 0.13552701359555935 0.12379524488343199
0.0 0.13060766191114231 0.11618447426663105
0.0 -0.0 0.20716602453458405
⋮ ⋱ ⋮
0.10960021189313257 0.0 0.11094174387120354
0.11196184769442043 0.0 0.10966622870818174
0.1115496686720318 0.0 0.10970771038082248
0.10985249024803737 0.0 … 0.10644013245886837
0.10734653247722736 0.0 0.10316144334132374
0.10918578734767424 0.0 0.10521880851067232
0.10834929035351762 0.0 0.10547950413651319
0.10650457785573118 0.0 0.10278488574177262
0.0 0.0 … 0.10091695075143108), :wealth => PortfolioOpt.WealthRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01"), Dates.Date("2010-12-02")]
And data, a 217-element Vector{Float64}:
1.0
1.004043437302107
1.0202303887788664
1.0070587774742485
0.9854664536358562
0.9910309597657923
0.9950883355571601
1.000583481647906
0.9789876757052475
0.9753863292008882
⋮
1.1539393095922201
1.1560936487758386
1.1595648969049797
1.1503998592100997
1.160801926795803
1.1595378469378816
1.1562190604616973
1.1511262663057789
1.1585028008715885), :returns => PortfolioOpt.ReturnsRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
And data, a 216-element Vector{Float64}:
0.004043437302106927
0.0161217641342831
-0.0129104283203946
-0.02144097675465071
0.005646570828875985
0.004094095902237762
0.005522269626112104
-0.0215832125342419
-0.003678643351424106
0.0011680686489537598
⋮
0.0029311006049640483
0.0018669432315116582
0.003002566559219948
-0.007903859214212586
0.009042132179019523
-0.0010889711920195457
-0.0028621631324485934
-0.0044046965926032135
0.006408102031658545)), nothing)
Backtest BenTal's robust return
backtest_results["Ben-Tal"], _ = sequential_backtest_market(
VolumeMarketHistory(returns_series), date_range,
) do market, past_returns, ext
numD, numA = size(past_returns)
returns = values(past_returns)
k_back = 30
Σ, r̄ = mean_variance(returns[(end - k_back):end, :])
d = MvNormal(r̄, Σ)
R = -0.015 / market_budget(market)
formulation = PortfolioFormulation(MAX_SENSE,
ObjectiveTerm(ExpectedReturn(d)),
RiskConstraint(ExpectedReturn(EllipticalSet(d, 2.0)), GreaterThan(R)),
)
pointers = change_bids!(market, formulation, Clarabel_SOLVER)
return pointers
end
(Dict{Symbol, PortfolioOpt.StateRecorder}(:decisions => PortfolioOpt.DecisionRecorder{Float64}(2-dimensional DenseAxisArray{Float64,2,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
Dimension 2, 1:6
And data, a 216×6 Matrix{Float64}:
1.9541462119732542e-8 7.026271875037349e-9 … 0.3421409337612164
3.960907287295588e-9 6.631861050397249e-9 0.33987060133774805
1.3407284661925974e-9 0.0651223420169545 0.30539619685501673
2.8044601648203983e-9 0.07426220781836933 0.30683342931704155
2.2879538375386375e-9 0.016657406505454712 0.29736403494754365
7.359992809269768e-9 0.11106934895290851 … 0.23824691768812378
1.20414532692836e-8 0.12727723877955963 0.23521750220076085
2.335676226760204e-9 0.09070945799150089 0.2632190360520086
9.925444602241768e-9 0.19776849032364086 0.1607704007202544
7.278094817890565e-10 0.0700029414935197 0.24191246600946725
⋮ ⋱ ⋮
7.166804746713069e-9 1.0772871265218471e-9 0.26327171070345645
8.351208466593402e-8 7.987067845360762e-9 0.16164072705185561
4.199109293234975e-9 5.304780445799851e-10 0.16572020828368958
4.244210090684159e-8 6.387695297318574e-9 … 0.13471016472399364
1.8625994438598678e-8 2.9239834049197745e-9 0.06102260286685821
6.7349776468423934e-9 1.671005278463826e-9 0.04745009689715881
1.0917791535062312e-8 2.0276431518644726e-9 0.10986374061657284
1.1766796422277999e-8 1.3728025933803183e-9 0.13622355558909593
7.190542657991347e-9 3.4796319574088654e-9 … 0.1655853162626334), :wealth => PortfolioOpt.WealthRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01"), Dates.Date("2010-12-02")]
And data, a 217-element Vector{Float64}:
1.0
1.0066085078882934
1.017082771297536
1.010917490580165
0.992529022404339
1.0007245829557507
1.0066711801346744
1.0109720227854153
0.9936284031242869
0.9883807619680404
⋮
1.1951435152056402
1.1937163779801603
1.1972137347249414
1.1856565902604
1.2034848559857616
1.2024019665654577
1.1903401633173114
1.1774781210325707
1.18754470209964), :returns => PortfolioOpt.ReturnsRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
And data, a 216-element Vector{Float64}:
0.006608507888293395
0.010405498589730828
-0.00606172957733401
-0.01818988032868323
0.008257250283279784
0.005942291495787712
0.004272341093708048
-0.017155390327561727
-0.005281291416133291
0.0007275340087722406
⋮
-0.003460782088446757
-0.0011941136836896608
0.0029298054456611622
-0.009653367756590845
0.015036618420386082
-0.0008997948041621483
-0.01003142342040554
-0.01080535016889293
0.008549272285621322)), nothing)
Backtest Betina's robust return
backtest_results["Betina"], _ = sequential_backtest_market(
VolumeMarketHistory(returns_series), date_range,
) do market, past_returns, ext
numD, numA = size(past_returns)
returns = values(past_returns)
k_back = 30
j_robust = 25
R = -0.015 / market_budget(market)
Σ, r̄ = mean_variance(returns[(end - k_back):end, :])
d = MvNormal(r̄, Σ)
formulation = PortfolioFormulation(MAX_SENSE,
ObjectiveTerm(ExpectedReturn(d)),
RiskConstraint(ConditionalExpectedReturn(DeterministicSamples(returns'[:, (end - j_robust):end]); α=0.0), GreaterThan(R)),
)
pointers = change_bids!(market, formulation, DEFAULT_SOLVER)
return pointers
end
(Dict{Symbol, PortfolioOpt.StateRecorder}(:decisions => PortfolioOpt.DecisionRecorder{Float64}(2-dimensional DenseAxisArray{Float64,2,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
Dimension 2, 1:6
And data, a 216×6 Matrix{Float64}:
0.0 0.0 0.0 … 0.2540909090909085
0.0 0.0 0.0 0.253157816077229
0.0 0.6137185446847665 0.0 0.0
0.0 0.6099549849010794 0.0 0.0
0.0 0.21204802641048387 0.0 0.16758912938636167
0.0 0.21032620965256546 0.0 … 0.16622831610124383
0.0 0.4731002693601723 0.0 0.0
0.0 0.21007840953985046 0.0 0.16603247082102715
0.0 0.43394409169277687 0.0 0.0
0.0 0.16439121677363955 0.0 0.19043039900320258
⋮ ⋱ ⋮
0.0 0.0 0.0 0.24588303002828832
0.0 0.0 0.0 0.24645308960922777
0.0 0.0 0.0 0.24666240630857042
0.0 0.0 0.0 … 0.0
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
0.0028475918799927055 0.0 0.0 0.2121355167856915
0.0 0.0 0.0 … 0.18627628419120565), :wealth => PortfolioOpt.WealthRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01"), Dates.Date("2010-12-02")]
And data, a 217-element Vector{Float64}:
1.0
1.003685815544383
1.0118303029248839
1.0180735240318015
0.9989636811544662
1.0071416082402296
1.011995852066605
1.008329592310504
0.9927416936197444
0.9860116099319938
⋮
1.170063782201865
1.1690708709083437
1.172231785304725
1.1631317480801486
1.1839803372023316
1.1828266167725399
1.1650848739777329
1.1483533787052287
1.1598597607037724), :returns => PortfolioOpt.ReturnsRecorder{Float64}(1-dimensional DenseAxisArray{Float64,1,...} with index sets:
Dimension 1, [Dates.Date("2010-01-26"), Dates.Date("2010-01-27"), Dates.Date("2010-01-28"), Dates.Date("2010-01-29"), Dates.Date("2010-02-01"), Dates.Date("2010-02-02"), Dates.Date("2010-02-03"), Dates.Date("2010-02-04"), Dates.Date("2010-02-05"), Dates.Date("2010-02-08") … Dates.Date("2010-11-17"), Dates.Date("2010-11-18"), Dates.Date("2010-11-19"), Dates.Date("2010-11-22"), Dates.Date("2010-11-23"), Dates.Date("2010-11-24"), Dates.Date("2010-11-26"), Dates.Date("2010-11-29"), Dates.Date("2010-11-30"), Dates.Date("2010-12-01")]
And data, a 216-element Vector{Float64}:
0.0036858155443830498
0.008114578540779065
0.0061702254704868965
-0.018770592129393616
0.008186410817570983
0.004819822541993041
-0.0036228011692084187
-0.01545913043674663
-0.006779289850526293
-0.0003938374594896225
⋮
-0.002313055120726208
-0.0008485958702634102
0.002703783384770584
-0.007763001599731331
0.017924529320599753
-0.0009744422213278007
-0.01499944501013777
-0.01436075229041553
0.010019896498686912)), nothing)
Plot
using Plots
using Plots.PlotMeasures
plt = plot(;title="Culmulative Wealth",
xlabel="Time",
ylabel="Wealth",
legend=:outertopright,
left_margin=10mm
);
for (strategy_name, recorders) in backtest_results
plot!(plt,
axes(get_records(recorders[:wealth]), 1), get_records(recorders[:wealth]).data;
label=strategy_name,
)
end
plt
This page was generated using Literate.jl.