# 量化交易 - 回測(Backtest)
> 強大的回測工具:backtesting. py
> Package使用方法: [官方文件](https://kernc.github.io/backtesting.py/doc/backtesting/backtesting.html#gsc.tab=0)
## Step0: 建議用Colab跑,安裝比較簡單
## Step1: 安裝所需套件
```
!pip install openai
!pip install yfinance
!pip install backtesting
!pip install bokeh==2.4.3 # 繪圖套件
from openai import OpenAI, OpenAIError # 串接 OpenAI API
import yfinance as yf
import pandas as pd # 資料處理套件
import datetime as dt # 時間套件
from backtesting import Backtest, Strategy # 回測套件
from backtesting.lib import crossover
```
## Step2: 安裝talib
```
url = 'https://anaconda.org/conda-forge/libta-lib/0.4.0/download/linux-64/libta-lib-0.4.0-h166bdaf_1.tar.bz2'
!curl -L $url | tar xj -C /usr/lib/x86_64-linux-gnu/ lib --strip-components=1
url = 'https://anaconda.org/conda-forge/ta-lib/0.4.19/download/linux-64/ta-lib-0.4.19-py310hde88566_4.tar.bz2'
!curl -L $url | tar xj -C /usr/local/lib/python3.10/dist-packages/ lib/python3.10/site-packages/talib --strip-components=3
```
## Step3: 取得該投資標的資料
```
import talib
# 輸入股票代號
stock_id = "2376.tw" # 以技嘉為例
# 抓取 5 年資料
df = yf.download(stock_id, period="5y") # 設定回測期間
# 計算指標
df['ma1'] = df['Close'].rolling(window=5).mean() # rolling(): 代表要滾動幾天的資料
df['ma2'] = df['Close'].rolling(window=10).mean()
df.tail()
```

## Step4: 定義回測策略
```
class Three_way_strategy(Strategy):
def init(self):
price = self.data.Close
# 初始化
self.ma5 = self.I(SMA,price,5)
self.ma20 = self.I(SMA,price,20)
# 初始化 KD
self.slow_k, self.slow_d = self.I(talib.STOCH, self.data.High, self.data.Low,self.data.Close,
fastk_period=9, slowk_period=3, slowd_period=3)
# 初始化RSI
self.RSI = self.I(talib.RSI, price, timeperiod = 14)
def next(self):
if crossover(self.ma5, self.ma20) and crossover(self.slow_k, self.slow_d) or self.RSI[-1] < 20:
self.buy()
elif crossover(self.ma20, self.ma5) and crossover(self.slow_d, self.slow_k) or self.RSI[-1] > 80:
if len(self.trades) > 0:
self.trades[0].close()
bt = Backtest(df, Three_way_strategy,cash = 150000, commission=0.004, exclusive_orders = True)
stats = bt.run()
```
## Step5: 回測結果
### 圖:
```
bt.plot()
```



> 從上面這張圖顯示的是我們累積的損益,若在這段時間內 從低點一直買到高點
- Peak: 我們最多賺了385%
- Final: 到目前是賺了383%
- Max Drawdown(最大回撤:回徹期間內的最大損失): 期間內的最大損失為-38.5%
- Max Dd Dur(Maximum Drawdown Duration): 可能會有 179 天都是賠錢的
### 詳細數據
```
print(stats)
```
```
Start 2019-04-09 00:00:00 開始日期
End 2024-04-09 00:00:00 結束日期
Duration 1827 days 00:00:00 回測總天數
Exposure Time [%] 34.675431 曝險期間,代表持有的部位佔總天數的百分比
Equity Final [$] 575027.93386 最終資產
Equity Peak [$] 577327.81586 最高資產
Return [%] 283.351956 總報酬率
Buy & Hold Return [%] 541.491405 買入並長期持有的總報酬率
Return (Ann.) [%] 32.081978 年化報酬率
Volatility (Ann.) [%] 39.073208 年化波動度
Sharpe Ratio 0.821074 夏普比率: 代表多承擔一單位風險的超額報酬
Sortino Ratio 1.792689 類似夏普比率,但只考慮下方風險(也就是股票下跌時的標準差)
Calmar Ratio 0.832427 年化報酬率/最大跌幅:用於衡量資產面臨最大風險時的表現
Max. Drawdown [%] -38.540274 最大損失:代表總資產在策略期間的最大下跌幅度
Avg. Drawdown [%] -6.480727 平均損失: 所有損失交易的平均數
Max. Drawdown Duration 182 days 00:00:00 最大損失的持續時間
Avg. Drawdown Duration 23 days 00:00:00 平均損失的持續時間
# Trades 7 交易次數
Win Rate [%] 71.428571 交易勝率,若以7次交易來說,超過半數以上的交易都是賺錢的
Best Trade [%] 108.773007 單一次交易的最佳報酬率
Worst Trade [%] -9.663671 單一次交易的最差報酬率
Avg. Trade [%] 21.165614 每筆交易的平均報酬率
Max. Trade Duration 264 days 00:00:00 單一筆交易的最常持有時間
Avg. Trade Duration 90 days 00:00:00 每筆交易平均持有時間
Profit Factor 19.358017 總獲利/總損失
Expectancy [%] 26.388541 用勝率來計算每筆交易的期望獲利
SQN 1.854045 衡量期望獲利、風險與交易次數的指標,通常>3就是不錯的策略
```
> 在stats中可以發現,win rate只是36%
> 可以發現當我們在做投資的時候 可能不是每筆交易都要賺錢,只要少數幾筆交易賺足夠多,那麼資產就能成長