Skip to content

Commit 3b65182

Browse files
committed
add param search
1 parent 8551d93 commit 3b65182

21 files changed

+3193
-12034
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# QuantResearch
22
Notebooks and Backtests
33

4-
54
|Index |Notebooks |Blogs |
65
|----:|:---------------------------------------------------------------------------------|-----------:|
7-
|0 | [Backtest](./backtest) |[data](./backtest/hist_downloader.py)|
8-
|0 | [Machine Learning](./ml) ||
6+
|* | [Backtest](./backtest) |[data downloader](./backtest/hist_downloader.py)|
7+
|* | [Machine Learning](./ml) ||
8+
|* | [Online Resources](./Resources.md) ||
99
|1 | [Portfolio Optimization One](./notebooks/portfolio_management_one.py) |[link](https://letianzj.github.io/portfolio-management-one.html)|
1010
|2 | [Value at Risk One](./notebooks/value_at_risk_one.py) |[link](https://letianzj.github.io/value-at-risk-one.html)|
1111
|3 | [Classical Linear Regression](./notebooks/classical_linear_regression.py) |[link](https://letianzj.github.io/classical-linear-regression.html)|

Resources.md

+189
Large diffs are not rendered by default.

backtest/README.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
# Backtest
22

3-
Test against daily bars between 2010 and 2019, using [Backtrader](https://www.backtrader.com/). It may not be fair to some intraday strategies.
3+
Test against daily bars between 2010 and 2019. It may not be fair to some intraday strategies.
4+
5+
[Examples of parameter search](./ma_double_cross.py).
6+
47

58
|Index |Backtest |Sharpe |
69
|----:|:---------------------------------------------------------------------------------|-----------:|
710
|1 | [Buy and Hold](./buy_hold.py) | 0.78 |
8-
|2 | [Moving Average cross](./ma_cross.py) | -0.51|
9-
|3 | [Moving Average double cross](./ma_double_cross.py) | 0.39|
11+
|2 | [Moving Average cross](./ma_cross.py) | -0.27|
12+
|3 | [Moving Average double cross](./ma_double_cross.py) | 0.32|
1013
|4 | [Bollinger Bands](./bollinger_bands.py) |0.46 |
1114
|5 | [Dual Thrust](./dual_thrust.py) | -0.55|
1215
|6 | [Ghost Trader](./ghost_trader.py) | -0.74|

backtest/Untitled.ipynb

-11,212
This file was deleted.
File renamed without changes.

backtest/bt/buy_hold.py

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import os
2+
import pandas as pd
3+
from datetime import datetime
4+
import backtrader as bt
5+
6+
class BuyAndHold(bt.Strategy):
7+
def __init__(self):
8+
# To keep track of pending orders and buy price/commission
9+
self.order = None
10+
11+
def log(self, txt, dt=None):
12+
''' Logging function fot this strategy'''
13+
dt = dt or self.datas[0].datetime.date(0)
14+
print('%s, %s' % (dt.isoformat(), txt))
15+
16+
def start(self):
17+
self.val_start = self.broker.get_cash() # keep the starting cash
18+
19+
def notify_trade(self, trade):
20+
if not trade.isclosed:
21+
return
22+
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm))
23+
24+
def notify_order(self, order):
25+
if order.status in [order.Submitted, order.Accepted]:
26+
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
27+
return
28+
29+
# Check if an order has been completed
30+
# Attention: broker could reject order if not enough cash
31+
if order.status in [order.Completed]:
32+
if order.isbuy():
33+
self.log(
34+
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
35+
(order.executed.price,
36+
order.executed.value,
37+
order.executed.comm))
38+
39+
self.buyprice = order.executed.price
40+
self.buycomm = order.executed.comm
41+
else: # Sell
42+
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
43+
(order.executed.price,
44+
order.executed.value,
45+
order.executed.comm))
46+
47+
self.bar_executed = len(self)
48+
49+
def next(self):
50+
# Simply log the closing price of the series from the reference
51+
# self.log('Close, %.2f' % self.data.close[0])
52+
# Buy all the available cash
53+
# self.order_target_value(target=self.broker.get_cash())
54+
#size = int(self.broker.get_cash() / self.data)
55+
#self.order = self.buy(size=size)
56+
self.buy()
57+
58+
def stop(self):
59+
# calculate the actual returns
60+
self.roi = (self.broker.get_value() / self.val_start) - 1.0
61+
print('ROI: {:.2f}%'.format(100.0 * self.roi))
62+
63+
64+
if __name__ == '__main__':
65+
# Create a cerebro entitysetsizing
66+
cerebro = bt.Cerebro()
67+
68+
datapath = os.path.join('../data/', 'SPX.csv')
69+
70+
# Create a Data Feed
71+
data = bt.feeds.YahooFinanceCSVData(
72+
dataname=datapath,
73+
# Do not pass values before this date
74+
fromdate=datetime(2010, 1, 1),
75+
# Do not pass values before this date
76+
todate=datetime(2019, 12, 31),
77+
# Do not pass values after this date
78+
reverse=False)
79+
80+
# Add the Data Feed to Cerebro
81+
cerebro.adddata(data)
82+
83+
# Set our desired cash start
84+
cerebro.broker.setcash(100000.0)
85+
86+
# Add a FixedSize sizer according to the stake
87+
# cerebro.addsizer(bt.sizers.FixedSize, stake=10)
88+
cerebro.addsizer(bt.sizers.PercentSizer, percents=95)
89+
90+
# Set the commission - 0.1% ... divide by 100 to remove the %
91+
cerebro.broker.setcommission(commission=0.001)
92+
# cheat-on-close
93+
cerebro.broker.set_coc(True) # doesn't seems to be working
94+
95+
# Print out the starting conditions
96+
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
97+
98+
# Add Analyzer
99+
cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
100+
101+
# Add a strategy
102+
cerebro.addstrategy(BuyAndHold)
103+
104+
# Run over everything
105+
results = cerebro.run()
106+
107+
# Print out the final result
108+
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
109+
cerebro.plot(style='candlestick')
110+
111+
strat = results[0]
112+
pyfoliozer = strat.analyzers.getbyname('pyfolio')
113+
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
114+
print('-------------- RETURNS ----------------')
115+
print(returns)
116+
print('-------------- POSITIONS ----------------')
117+
print(positions)
118+
print('-------------- TRANSACTIONS ----------------')
119+
print(transactions)
120+
print('-------------- GROSS LEVERAGE ----------------')
121+
print(gross_lev)
122+
123+
import empyrical as ep
124+
import pyfolio as pf
125+
import matplotlib.pyplot as plt
126+
perf_stats_strat = pf.timeseries.perf_stats(returns)
127+
drawdown_table = pf.timeseries.gen_drawdown_table(returns, 5)
128+
monthly_ret_table = ep.aggregate_returns(returns, 'monthly')
129+
monthly_ret_table = monthly_ret_table.unstack().round(3)
130+
ann_ret_df = pd.DataFrame(ep.aggregate_returns(returns, 'yearly'))
131+
ann_ret_df = ann_ret_df.unstack().round(3)
132+
print('-------------- PERFORMANCE ----------------')
133+
print(perf_stats_strat)
134+
print('-------------- DRAWDOWN ----------------')
135+
print(drawdown_table)
136+
print('-------------- MONTHLY RETURN ----------------')
137+
print(monthly_ret_table)
138+
print('-------------- ANNUAL RETURN ----------------')
139+
print(ann_ret_df)
140+
141+
pf.create_full_tear_sheet(
142+
returns,
143+
positions=positions,
144+
transactions=transactions,
145+
#live_start_date='2005-05-01',
146+
round_trips=False)
147+
plt.show()
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)