Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Python 回測框架(三)技術指標

出處:https://stockbuzzai.wordpress.com/2019/07/10/python-%e5%9b%9e%e6%b8%ac%e6%a1%86%e6%9e%b6%ef%bc%88%e4%b8%89%ef%bc%89%e6%8a%80%e8%a1%93%e6%8c%87%e6%a8%99/

延續之前的內容,這次要利用最頻繁被使用的技術指標之一 – 日均線 (Moving Average) 作為我們策略的篩選條件。

在投資策略上,技術指標是一個很常被用到的工具。透過技術指標,我們可以比較容易地分析商品或是大盤的趨勢。在這個範例之中,我們將使用 20 日均線和 60 日均線做為我們買賣的參考。當商品 (MSFT) 的開盤價低於 60 日均線同時 20 均線又呈現上漲趨勢的時候,我們才買入商品。

data = backtrader.feeds.YahooFinanceData(dataname='MSFT',
                                  fromdate=datetime(2009, 1, 1),
                                  todate=datetime(2018, 12, 31)) 

雖然我們是從 2010 年才開始交易,但是因為我們有需要 60 天均線和 20 天均線的資料,因此我們必須至少多載入 60 個交易日以上的資料來提供系統計算均線。

def __init__(self):
         self.next_buy_date = datetime(2010, 1, 1)
         self.sma60 = backtrader.ind.SMA(period=60)
         self.sma20 = backtrader.ind.SMA(period=20)
         self.total_cash = 0 

在初始化的過程中,我們產生了兩個均線變數,sma20 和 sma60。同時我們產生一個變數 total_cash 來統計我們到底投入的多少資金。next_buy_day則是控制不要短期內連續買入。

current_date = self.data.datetime.date()
         if current_date >= self.next_buy_date.date():
             if self.data.close < self.sma60[0] and self.sma20[0] > self.sma20[-1]:
                 price = (self.data.high + self.data.low) / 2.0
                 volume = math.floor((self.broker.cash) / price)
                 self.buy(size=volume)
                 self.broker.add_cash(cash=300)
                 self.total_cash += 300
                 self.next_buy_date = datetime.combine(current_date, datetime.min.time()) + relativedelta(months=1)  

首先,if current_date >= self.next_buy_date.date(): 這一行判斷了是否今天是可以交易的日子。self.data.close < self.sma60[0] 則判斷了今日的開盤價是否高於 60 日均線。self.sma20[0] > self.sma20[-1] 這一行則判斷今日的 20 日均線值是否比昨天高,用來判斷20 天均線是否在上升的狀態。

當這兩個條件都成立,則買入。

根據程式回測的結果,我們只需要投入 7800 元,9 年後微軟的淨值就會成為 25474,大約賺了250% 以上。

img微軟 (MSFT)

___

完整程式碼

from datetime import datetime
from dateutil.relativedelta import relativedelta
import backtrader
import math
  
class TestStrategy(backtrader.Strategy):
     def __init__(self):
         self.next_buy_date = datetime(2010, 1, 1)
         self.sma60 = backtrader.ind.SMA(period=60)
         self.sma20 = backtrader.ind.SMA(period=20)
         self.total_cash = 0
  
     def next(self):
         current_date = self.data.datetime.date()
         if current_date >= self.next_buy_date.date():
             if self.data.close < self.sma60[0] and self.sma20[0] > self.sma20[-1]:
                 price = (self.data.high + self.data.low) / 2.0
                 volume = math.floor((self.broker.cash) / price)
                 self.buy(size=volume)
                 self.broker.add_cash(cash=300)
                 self.total_cash += 300
                 self.next_buy_date = datetime.combine(current_date, datetime.min.time()) + relativedelta(months=1)
  
     def stop(self):
         print(self.total_cash)
  
 cerebro = backtrader.Cerebro()
 data = backtrader.feeds.YahooFinanceData(dataname='MSFT',
                                  fromdate=datetime(2009, 1, 1),
                                  todate=datetime(2018, 12, 31))
  
 cerebro.adddata(data) 
 cerebro.addstrategy(TestStrategy)
 cerebro.broker.set_cash(cash=300)
 cerebro.run()
 cerebro.plot()