量化交易學習筆記(十九)——連續下跌買入止盈止損賣出策略

量化交易學習筆記(十九)——連續下跌買入止盈止損賣出策略

好友提出要驗證連續下跌買入止盈止損賣出策略,本文對該策略回測和實現做分析記錄。

買入條件中,連續下跌定義為收盤價連續4日低於前1日的收盤價。賣出條件中,止盈率設置為10%,止損率設置為5%。回測初始資金100000元,單筆操作單位1000股,佣金千分之一,回測時間自2018年1月1日至2020年3月6日。

策略核心代碼位於策略類的next方法中:

<code>

def

next

(

self

)

:

if

self

.

orefs:

return

if

not

self

.

position:

lastcloses = list()

for

i

in

range(

self

.p.p_downdays +

1

): lastcloses.append(

self

.dataclose[-i])

if

lastcloses == sorted(lastcloses): close =

self

.dataclose[

0

] p1 = close * (

1.0

-

self

.p.limit) p2 = p1 -

self

.p.p_stoploss * close p3 = p1 +

self

.p.p_takeprofit * close valid1 = datetime.timedelta(

self

.p.limdays) valid2 = valid3 = datetime.timedelta(

self

.p.limdays2) os =

self

.buy_bracket( price=p1, valid=valid1, stopprice=p2, stopargs=dict(valid=valid2), limitprice=p3, limitargs=dict(valid=valid3),)

self

.orefs = [o.ref

for

o

in

os]/<code>

這裡主要應用了backtrader的bracket order,它其實並不是1個訂單,而是有3個訂單構成:1個買單,1個止損賣單,1個止盈賣單。2個賣單就像是把買單用括號括起來一樣,因此合稱為bracket order(括號訂單)。我們所使用的buy_bracket方法遵循以下規則:

  • 為了避免被分開執行,3個訂單要被一起提交
  • 2個賣單要作為買單的子訂單
  • 在買單執行前,2個賣單處於非激活狀態
  • 買單如果被取消,2個賣單也會隨之被取消
  • 買單被執行後,2個賣單均被激活
  • 一旦兩個賣單被激活,其中一個被執行或者被取消,另一個都將被自動取消。

buy_bracket方法中除了設置買入價、止損價、止盈價外,還設置了訂單有效時間,如果訂單在有效時間內未執行,則會過期失效。一般我們將買入有效期設置為3天以內,賣出有效期設置為較長時間,以保證股票可以賣出。

回測000001後的最終資產為104779.07元,這裡交易大小僅為1000股,所用資金僅為不到20000元,提高交易量,收益還是相當可觀。

量化交易學習筆記(十九)——連續下跌買入止盈止損賣出策略

回測000002後的最終資產為97984.31元,微虧。

量化交易學習筆記(十九)——連續下跌買入止盈止損賣出策略

回測601318後的最終資產為87626.32元,虧損。

量化交易學習筆記(十九)——連續下跌買入止盈止損賣出策略

觀察幾張圖標可以發現,我們經常可以找到很好的買點,但是會出現本來盈利的訂單,最後變成虧損的情況。今天在挖backtrader文檔的時候,發現了一個比較好的利潤保護方法,計劃在下一篇文章中進行實現及分析,敬請期待。

友情提示:本系列學習筆記只做數據分析,記錄個人學習過程,不作為交易依據,盈虧自負。

連續下跌買入止盈止損賣出策略代碼:

<code>

from

__future__ import (absolute_import, division, print_function, unicode_literals)

import

datetime # 用於datetime對象操作

import

os.path # 用於管理路徑

import

sys # 用於在argvTo[0]中找到腳本名稱

import

backtrader as bt # 引入backtrader框架

class

St(bt.Strategy):

params

=

dict(

p_downdays

=

4, # 連續下跌天數

p_stoploss

=

0.05, # 止損比例

p_takeprofit

=

0.1, # 止盈比例

limit

=

0.005,

limdays

=

3,

limdays2

=

1000,

hold

=

10,

usebracket

=

False, # use order_target_size

switchp1p2

=

False, # switch prices of order1 and order2

)

def

notify_order(self, order):

if

not order.alive() and order.ref in self.orefs:

self.orefs.remove(order.ref)

def

__init__(self):

=

self.datas[0].close

sma

=

bt.ind.SMA(period = self.p.p_downdays + 1, plot = False)

=

list()

def

next(self):

if

self.orefs: # order列表,用於存儲尚未執行完成的訂單

return

# 有尚未執行的訂單

if

not self.position:

lastcloses

=

list()

for

i in range(self.p.p_downdays + 1):

lastcloses.append(self.dataclose[-i])

if

lastcloses == sorted(lastcloses):

close

=

self.dataclose[0]

p1

=

close * (1.0 - self.p.limit)

p2

=

p1 - self.p.p_stoploss * close

p3

=

p1 + self.p.p_takeprofit * close

valid1

=

datetime.timedelta(self.p.limdays)

valid2

=

valid3 = datetime.timedelta(self.p.limdays2)

os

=

self.buy_bracket(

price

=

p1, valid=valid1,

stopprice

=

p2, stopargs=dict(valid=valid2),

limitprice

=

p3, limitargs=dict(valid=valid3),)

=

[o.ref for o in os]

cerebro

=

bt.Cerebro() # 創建cerebro

modpath

=

os.path.dirname(os.path.abspath(sys.argv[0]))

datapath

=

os.path.join(modpath, '../TQDat/day/stk/000002.csv')

data

=

bt.feeds.GenericCSVData(

dataname

=

datapath,

fromdate

=

datetime.datetime(2018, 1, 1),

todate

=

datetime.datetime(2020, 3, 31),

nullvalue

=

0.0,

dtformat

=

('%Y-%m-%d'),

datetime

=

0,

open

=

1,

high

=

2,

low

=

3,

close

=

4,

volume

=

5,

openinterest

=

-1

)

cerebro.adddata(data)

cerebro.broker.setcash(100000.0)

stake = 1000)

=

0.001)

# 添加策略

# 遍歷所有數據

Portfolio Value: %.2f' % cerebro.broker.getvalue())

# 繪圖

/<code>


分享到:


相關文章: