Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions AAPL_backtest_summary.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
,0
Start,2024-01-02 00:00:00
End,2025-05-05 00:00:00
Duration,489 days 00:00:00
Exposure Time [%],16.36904761904762
Equity Final [$],8805.002468226288
Equity Peak [$],10381.560838839165
Commissions [$],703.7577009236095
Return [%],-11.949975317737117
Buy & Hold Return [%],6.405078007938552
Return (Ann.) [%],-9.103510330147934
Volatility (Ann.) [%],15.097975067477131
CAGR [%],-6.348004908513937
Sharpe Ratio,-0.6029623369664981
Sortino Ratio,-0.9818176087321079
Calmar Ratio,-0.4064775510211833
Alpha [%],-13.556641469466234
Beta,0.250842558004413
Max. Drawdown [%],-22.39609618606837
Avg. Drawdown [%],-9.291759364005102
Max. Drawdown Duration,216 days 00:00:00
Avg. Drawdown Duration,106 days 00:00:00
# Trades,18
Win Rate [%],50.0
Best Trade [%],3.8041930176504923
Worst Trade [%],-4.691479431007584
Avg. Trade [%],-0.3131544650804563
Max. Trade Duration,9 days 00:00:00
Avg. Trade Duration,3 days 00:00:00
Profit Factor,0.7201229237144986
Expectancy [%],-0.28801010963268897
SQN,-0.5212739426429492
Kelly Criterion,-0.18930867823349662
_strategy,BollingerBandsStrategy
_equity_curve," Equity DrawdownPct DrawdownDuration
Date
2024-01-02 10000.000000 0.000000 NaT
2024-01-03 10000.000000 0.000000 NaT
2024-01-04 10000.000000 0.000000 NaT
2024-01-05 10000.000000 0.000000 NaT
2024-01-08 10000.000000 0.000000 NaT
... ... ... ...
2025-04-29 8805.002468 0.151861 NaT
2025-04-30 8805.002468 0.151861 NaT
2025-05-01 8805.002468 0.151861 NaT
2025-05-02 8805.002468 0.151861 NaT
2025-05-05 8805.002468 0.151861 216 days

[336 rows x 3 columns]"
_trades," Size EntryBar ExitBar EntryPrice ExitPrice SL TP PnL ReturnPct EntryTime ExitTime Duration Tag Entry_λ(C) Exit_λ(C) Entry_λ(λ(C),λ(C)) Exit_λ(λ(C),λ(C))
0 58 43 47 169.957487 172.127235 None None 125.845376 0.012766 2024-03-05 2024-03-11 6 days None 4.527633 5.663169 173.048741 167.117081
1 -55 86 88 181.493040 181.990679 None None -27.370115 -0.002742 2024-05-06 2024-05-08 2 days None 4.763007 5.743741 160.837056 160.253583
2 -48 112 115 206.675374 212.655280 None None -287.035500 -0.028934 2024-06-12 2024-06-17 5 days None 6.014026 9.233323 180.991226 178.238745
3 -44 116 117 216.861138 213.213410 None None 160.500049 0.016821 2024-06-18 2024-06-20 2 days None 9.805533 9.984093 178.252929 178.759407
4 -42 131 132 230.614920 228.153193 None None 103.392568 0.010675 2024-07-11 2024-07-12 1 days None 7.516048 7.976927 201.493680 201.442496
5 48 149 151 204.612315 212.396162 None None 373.624675 0.038042 2024-08-06 2024-08-08 2 days None 7.301858 7.491392 207.374232 205.130431
6 47 178 179 215.276194 217.072249 None None 84.414566 0.008343 2024-09-17 2024-09-18 1 days None 3.698915 3.693978 215.793450 215.512965
7 -44 188 189 229.015955 225.393922 None None 159.369429 0.015816 2024-10-01 2024-10-02 1 days None 4.184788 4.166177 215.068660 215.401730
8 -44 199 200 231.091399 232.917370 None None -80.342753 -0.007902 2024-10-16 2024-10-17 1 days None 2.739419 2.876051 222.098788 221.989163
9 -43 203 204 233.376366 233.565951 None None -8.152167 -0.000812 2024-10-22 2024-10-23 1 days None 3.876052 3.816264 221.251383 221.589978
10 46 213 214 221.312919 222.121137 None None 37.178020 0.003652 2024-11-05 2024-11-06 1 days None 4.066379 4.390473 221.698410 220.709971
11 -43 229 235 234.212496 242.643218 None None -362.521083 -0.035996 2024-11-27 2024-12-06 9 days None 3.779119 6.652274 219.357893 218.878670
12 41 258 260 233.273523 234.382301 None None 45.459892 0.004753 2025-01-13 2025-01-15 2 days None 6.533045 7.651944 235.261381 231.777951
13 42 262 263 231.865066 223.753984 None None -340.665438 -0.034982 2025-01-17 2025-01-21 4 days None 9.160005 10.338023 226.450372 222.825231
14 42 264 265 219.548596 224.493183 None None 207.672666 0.022522 2025-01-22 2025-01-23 1 days None 11.100430 11.458420 220.003843 217.748055
15 -39 282 283 244.149994 244.660004 None None -19.890381 -0.002089 2025-02-18 2025-02-19 1 days None 6.862813 6.937019 218.889607 219.864920
16 42 297 301 223.809998 213.309998 None None -441.000000 -0.046915 2025-03-11 2025-03-17 6 days None 6.620664 12.090305 225.878672 209.865890
17 46 315 319 193.889999 189.070007 None None -221.719635 -0.024859 2025-04-04 2025-04-10 6 days None 8.593759 15.168659 199.377983 179.636684"
19 changes: 19 additions & 0 deletions AAPL_trades.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Size,EntryBar,ExitBar,EntryPrice,ExitPrice,SL,TP,PnL,ReturnPct,EntryTime,ExitTime,Duration,Tag,Entry_λ(C),Exit_λ(C),"Entry_λ(λ(C),λ(C))","Exit_λ(λ(C),λ(C))"
58,43,47,169.95748724050745,172.12723509594798,,,125.84537561555095,0.012766415241066253,2024-03-05,2024-03-11,6 days,,4.527632575567383,5.663169097164208,173.0487410439336,167.11708068994892
-55,86,88,181.49304025440043,181.9906787165348,,,-27.37011541739065,-0.0027419148493894596,2024-05-06,2024-05-08,2 days,,4.763007498391218,5.743741067026366,160.83705644486795,160.25358308201172
-48,112,115,206.67537368785207,212.65527993528355,,,-287.0354998767107,-0.028933811226407258,2024-06-12,2024-06-17,5 days,,6.01402647066493,9.23332282211707,180.99122577571114,178.23874528594163
-44,116,117,216.86113841241473,213.21341001933183,,,160.5000492956476,0.016820572001913225,2024-06-18,2024-06-20,2 days,,9.805533381516616,9.984093209379408,178.25292936123435,178.75940681244236
-42,131,132,230.61492037011672,228.1531925563972,,,103.39256817622044,0.010674625083965439,2024-07-11,2024-07-12,1 days,,7.516048380054616,7.976926920488966,201.49367991225407,201.4424962566783
48,149,151,204.61231506511243,212.39616246807245,,,373.624675342081,0.03804193017650492,2024-08-06,2024-08-08,2 days,,7.30185805300242,7.4913924989886445,207.37423189204205,205.1304314021692
47,178,179,215.27619443719672,217.07224903728172,,,84.41456620399501,0.008343024665502297,2024-09-17,2024-09-18,1 days,,3.6989154418878405,3.693977513044931,215.79345024415403,215.5129650788906
-44,188,189,229.0159547825387,225.3939223013361,,,159.3694291729148,0.0158156338262192,2024-10-01,2024-10-02,1 days,,4.184788347706843,4.166176946026622,215.06865954115858,215.4017304280151
-44,199,200,231.09139869260778,232.9173703418766,,,-80.34275256782757,-0.007901512819599388,2024-10-16,2024-10-17,1 days,,2.739418600500189,2.8760508937308353,222.09878807365783,221.98916331873951
-43,203,204,233.376366009758,233.56595129753524,,,-8.15216737442168,-0.0008123585563473146,2024-10-22,2024-10-23,1 days,,3.876052441609934,3.8162640634156557,221.25138327595982,221.58997782409642
46,213,214,221.31291912362707,222.12113695305962,,,37.17802015389731,0.003651923406157165,2024-11-05,2024-11-06,1 days,,4.066378859333006,4.3904728217626126,221.69840988387307,220.70997079934585
-43,229,235,234.21249554010248,242.6432183998472,,,-362.5210829690229,-0.03599604214242791,2024-11-27,2024-12-06,9 days,,3.779119488016085,6.652274043551948,219.3578926157647,218.87866953374572
41,258,260,233.27352322575203,234.38230107288462,,,45.459891732436034,0.004753123422667871,2025-01-13,2025-01-15,2 days,,6.533044680637922,7.651944030740078,235.26138103667336,231.77795092777765
42,262,263,231.86506609768284,223.75398423747347,,,-340.6654381287934,-0.034981905626060295,2025-01-17,2025-01-21,4 days,,9.160004797200305,10.33802288197377,226.45037157015017,222.82523063375754
42,264,265,219.54859611049605,224.493183388126,,,207.67266566045788,0.022521607358133133,2025-01-22,2025-01-23,1 days,,11.100429518709664,11.458420096250016,220.00384295843028,217.74805467444332
-39,282,283,244.14999389648438,244.66000366210938,,,-19.890380859375,-0.0020889198377012086,2025-02-18,2025-02-19,1 days,,6.862813174493649,6.937019138117408,218.8896065001338,219.86492046399957
42,297,301,223.80999755859375,213.30999755859375,,,-441.0,-0.046914794310075836,2025-03-11,2025-03-17,6 days,,6.620663711930269,12.090304654568454,225.8786722709637,209.86589032465216
46,315,319,193.88999938964844,189.07000732421875,,,-221.71963500976562,-0.02485941554800486,2025-04-04,2025-04-10,6 days,,8.593758627796822,15.16865893252575,199.3779833852755,179.6366842101438
61 changes: 61 additions & 0 deletions BollingerBandsStrategy.html

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions strategy/bollinger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import yfinance as yf
import numpy as np
import pandas as pd
from backtesting import Backtest, Strategy
import sys

# Custom rolling mean
def rolling_mean(x, window):
result = np.full_like(x, np.nan, dtype=np.float64)
for i in range(window - 1, len(x)):
result[i] = np.mean(x[i - window + 1:i + 1])
return result

# Custom rolling std
def rolling_std(x, window):
result = np.full_like(x, np.nan, dtype=np.float64)
for i in range(window - 1, len(x)):
result[i] = np.std(x[i - window + 1:i + 1])
return result

# ✅ Strategy class
class BollingerBandsStrategy(Strategy):
def init(self):
close = self.data.Close
window = 20
self.ma = self.I(lambda x: rolling_mean(x, window), close)
self.std = self.I(lambda x: rolling_std(x, window), close)
self.upper = self.I(lambda ma, std: ma + 2 * std, self.ma, self.std)
self.lower = self.I(lambda ma, std: ma - 2 * std, self.ma, self.std)

def next(self):
price = self.data.Close[-1]
ma, upper, lower = self.ma[-1], self.upper[-1], self.lower[-1]

if np.isnan(ma) or np.isnan(upper) or np.isnan(lower):
return

if price < lower:
self.buy()
elif price > upper:
self.sell()
elif self.position:
self.position.close()

# ✅ Backtest runner
def run_strategy(ticker="AAPL"):
print(f"\n📈 Running strategy on {ticker}...\n")
df = yf.download(ticker, start="2024-01-01", end="2025-05-06", auto_adjust=True)

# Flatten MultiIndex columns if needed
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0) # Get the first level of the MultiIndex

# Ensure proper structure
try:
df = df[['Open', 'High', 'Low', 'Close', 'Volume']].dropna()
except KeyError as e:
print(f"❌ KeyError: {e}")
return

df.index.name = 'Date'

if df.empty:
print(f"❌ No data for {ticker}.")
return

bt = Backtest(df, BollingerBandsStrategy, cash=10000, commission=0.002)
stats = bt.run()

# Print key stats
print(stats[['Start', 'End', 'Duration', 'Return [%]', 'Sharpe Ratio', 'Max. Drawdown [%]', '# Trades']])

# Export results
stats['_trades'].to_csv(f"{ticker}_trades.csv", index=False)
stats.to_frame().to_csv(f"{ticker}_backtest_summary.csv")
print(f"\n✅ Exported: {ticker}_trades.csv and {ticker}_backtest_summary.csv")

bt.plot()

# ✅ Main entry
if __name__ == "__main__":
ticker = sys.argv[1] if len(sys.argv) > 1 else "AAPL"
run_strategy(ticker)