KDJ指標在指數上的趨勢與擇時效應

"""導入常用模塊"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
from environment import * # 導入大樹工作室開發的回測模塊

KDJ指標計算函數

import talib as tl
from functools import reduce

# SMA計算函數
def SMA(close, timeperiod) :
    close = np.nan_to_num(close)
    return reduce(lambda x, y: ((timeperiod - 1) * x + y) / timeperiod, close)
    
# KDJ計算函數
def KDJ(high, low, close, fastk_period, slowk_period, fastd_period) :
    kValue, dValue = tl.STOCHF(high, low, close, fastk_period, fastd_period=1, fastd_matype=0)
    
    kValue = np.array(list(map(lambda x : SMA(kValue[:x], slowk_period), range(1, len(kValue) + 1))))
    dValue = np.array(list(map(lambda x : SMA(kValue[:x], fastd_period), range(1, len(kValue) + 1))))
    
    jValue = 3 * kValue - 2 * dValue
    
    func = lambda arr : np.array([0 if x < 0 else (100 if x > 100 else x) for x in arr])
    
    kValue = func(kValue)
    dValue = func(dValue)
    jValue = func(jValue)
    return kValue, dValue, jValue

# 獲取某標的的KDJ信息
def get_kdj(stock, count, end_date, unit):
    data = get_bars(security=stock, count=count, unit=unit,
                        include_now=False, 
                        end_dt=end_date, fq_ref_date=None)
    close = data['close']
    open = data['open']
    high = data['high']
    low = data['low']

    return KDJ(high, low, close, 9, 3, 3) 

KDJ的使用方法可以參考:https://www.joinquant.com/view/community/detail/16464

KDJ指標使用方法 一

KDJ是一種擺動指標,20與80的位置是我們對當前超買超賣狀態的最基本判斷。接下來的擇時條件如下:

  • 當D線處於20位置以下時,買進;
  • 當D線處於80位置以上時,賣出;

另外,20與80的位置並不是硬性指標,我們可以爲其指定一個浮動範圍;我們將這個範圍N值定在1%~9%之間,然後做回測,並查看其結果。

trade_list = []
N =[n/100 for n in range(1, 10)]

for n in N:
    """初始化以下內容"""
    context = Context() # 賬戶對象
    order = Order(context) # 下單對象
    trade = Trade(context, order) # 回測對旬
    context.start_date = '2005-05-01'
    context.end_date = '2019-02-22'
    context.universe = ['000300.XSHG']
    context.base = '000300.XSHG'

    """策略主體"""
    def handle(context, order):
        stock = context.universe[0]
        current_date = trade.context.current_dt
        kdj_day = get_kdj(stock, 30, current_date, '1d')
        
        line_bottm = 20 * (1+n)
        line_top = 80 * (1-n)

        k1 = kdj_day[0][-1]
        d1 = kdj_day[1][-1]
        j1 = kdj_day[2][-1]

        k2 = kdj_day[0][-2]
        d2 = kdj_day[1][-2]
        j2 = kdj_day[2][-2]

        close = get_price(security=stock, 
                          end_date=context.current_dt,
                          frequency='daily', 
                          fields=None, 
                          skip_paused=False, 
                          fq='pre',
                          count=5)['close']

        if d2 > line_bottm and d1 < line_bottm :
            if stock in context.position.keys():
                return
            order.buy(stock, close[-1], context.cash // close[-1])
        elif d2 < line_top and d1 > line_top:
            if stock not in context.position.keys():
                return
            order.sell(stock, close[-1], context.position[stock]['count'])

    """執行策略"""
    trade.trade(handle, show=False, log=True)
    trade_list.append(trade)
# 展示
Trade.show_ratio_compare('n', N, trade_list, 3, 3)
End Time : 2019-03-10 16:01:27.192853, Elapsed Time: 0:00:18.351210
End Time : 2019-03-10 16:01:45.031913, Elapsed Time: 0:00:17.838861
End Time : 2019-03-10 16:02:02.843599, Elapsed Time: 0:00:17.811513
End Time : 2019-03-10 16:02:20.318987, Elapsed Time: 0:00:17.475214
End Time : 2019-03-10 16:02:38.392089, Elapsed Time: 0:00:18.072942
End Time : 2019-03-10 16:02:55.567773, Elapsed Time: 0:00:17.175470
End Time : 2019-03-10 16:03:13.802732, Elapsed Time: 0:00:18.234765
End Time : 2019-03-10 16:03:32.918843, Elapsed Time: 0:00:19.115479
End Time : 2019-03-10 16:03:51.401436, Elapsed Time: 0:00:18.482391
Trade.show_result('n', N, trade_list)

從上圖來看,kdj在超買與超賣區的反應對於滬深300指數來說,反應並不好。

KDJ使用方法 二

  • 當k線與d線形成金叉時買進;
  • 當k線與d線形成死叉時賣出;

金叉與死叉形成時,最小的時間段是前天與當天的值的比較,這個時間段也可以被當作一種參數D,其取值範圍是1~9天。查看回測結果:

trade_list = []
D = range(1, 10)

for d in D:
    """初始化以下內容"""
    context = Context() # 賬戶對象
    order = Order(context) # 下單對象
    trade = Trade(context, order) # 回測對旬
    context.start_date = '2005-05-01'
    context.end_date = '2019-02-22'
    context.universe = ['000300.XSHG']
    context.base = '000300.XSHG'

    """策略主體"""
    def handle(context, order):
        stock = context.universe[0]
        current_date = trade.context.current_dt
        kdj_day = get_kdj(stock, 30, current_date, '1d')

        k1 = kdj_day[0][-1]
        d1 = kdj_day[1][-1]
        j1 = kdj_day[2][-1]

        k2 = kdj_day[0][-d-1]
        d2 = kdj_day[1][-d-1]
        j2 = kdj_day[2][-d-1]

        close = get_price(security=stock, 
                          end_date=context.current_dt,
                          frequency='daily', 
                          fields=None, 
                          skip_paused=False, 
                          fq='pre',
                          count=5)['close']

        if k2 < d2 and k1 > d1:
            if stock in context.position.keys():
                return
            order.buy(stock, close[-1], context.cash // close[-1])
        elif k2 > d2 and k1 < d1:
            if stock not in context.position.keys():
                return
            order.sell(stock, close[-1], context.position[stock]['count'])

    """執行策略"""
    trade.trade(handle, show=False, log=True)
    trade_list.append(trade)
# 展示
Trade.show_ratio_compare('d', D, trade_list, 3, 3)
End Time : 2019-03-10 16:04:13.577469, Elapsed Time: 0:00:20.034098
End Time : 2019-03-10 16:04:33.005696, Elapsed Time: 0:00:19.428044
End Time : 2019-03-10 16:04:52.154929, Elapsed Time: 0:00:19.149037
End Time : 2019-03-10 16:05:12.142793, Elapsed Time: 0:00:19.987659
End Time : 2019-03-10 16:05:31.073016, Elapsed Time: 0:00:18.930031
End Time : 2019-03-10 16:05:51.557113, Elapsed Time: 0:00:20.483901
End Time : 2019-03-10 16:06:10.902478, Elapsed Time: 0:00:19.345159
End Time : 2019-03-10 16:06:29.924519, Elapsed Time: 0:00:19.021839
End Time : 2019-03-10 16:06:48.871547, Elapsed Time: 0:00:18.946834
Trade.show_result('d', D, trade_list)

從上面結果來看,當d=2時回測的效果比較好,但整體看來,仍舊沒有跑贏大盤。因此,效果也並不理想。

KDJ使用方法 三

  • 當j線與價格發生底背離時,買進;
  • 當j線與價格發生頂背離時,賣出;

背離計算的是一段時間內,j線的趨勢與價格的趨勢在方向上不一致,把時間段設爲D值,取值範圍是1~9天。回測並查看結果:

trade_list = []
D = range(1, 10)

for d in D:
    """初始化以下內容"""
    context = Context() # 賬戶對象
    order = Order(context) # 下單對象
    trade = Trade(context, order) # 回測對旬
    context.start_date = '2005-05-01'
    context.end_date = '2019-02-22'
    context.universe = ['000300.XSHG']
    context.base = '000300.XSHG'

    """策略主體"""
    def handle(context, order):
        stock = context.universe[0]
        current_date = trade.context.current_dt
        kdj_day = get_kdj(stock, 30, current_date, '1d')

        k1 = kdj_day[0][-1]
        d1 = kdj_day[1][-1]
        j1 = kdj_day[2][-1]

        k2 = kdj_day[0][-d-1]
        d2 = kdj_day[1][-d-1]
        j2 = kdj_day[2][-d-1]

        close = get_price(security=stock, 
                          end_date=context.current_dt,
                          frequency='daily', 
                          fields=None, 
                          skip_paused=False, 
                          fq='pre',
                          count=20)['close']

        if j1 > j2 and close[-1] < close[-d-1]:
            if stock in context.position.keys():
                return
            order.buy(stock, close[-1], context.cash // close[-1])
        elif j1 < j2 and close[-1] > close[-d-1]:
            if stock not in context.position.keys():
                return
            order.sell(stock, close[-1], context.position[stock]['count'])

    """執行策略"""
    trade.trade(handle, show=False, log=True)
    trade_list.append(trade)
# 展示
Trade.show_ratio_compare('d', D, trade_list, 3, 3)
End Time : 2019-03-10 16:07:10.097162, Elapsed Time: 0:00:19.401507
End Time : 2019-03-10 16:07:30.041172, Elapsed Time: 0:00:19.943802
End Time : 2019-03-10 16:07:51.642053, Elapsed Time: 0:00:21.600708
End Time : 2019-03-10 16:08:12.491229, Elapsed Time: 0:00:20.848990
End Time : 2019-03-10 16:08:32.879961, Elapsed Time: 0:00:20.388533
End Time : 2019-03-10 16:08:53.409177, Elapsed Time: 0:00:20.528626
End Time : 2019-03-10 16:09:12.488550, Elapsed Time: 0:00:19.079192
End Time : 2019-03-10 16:09:32.450308, Elapsed Time: 0:00:19.961573
End Time : 2019-03-10 16:09:52.517584, Elapsed Time: 0:00:20.067092
Trade.show_result('d', D, trade_list)

從上圖來看,j線的背離效果也不好,k線與d線的背離效果這裏就不做加測了。

下面展示本次研究效果最好的參數,即金叉與死叉條件下,d=2時的結果。

"""初始化以下內容"""
context = Context() # 賬戶對象
order = Order(context) # 下單對象
trade = Trade(context, order) # 回測對旬
context.start_date = '2005-05-01'
context.end_date = '2019-02-22'
context.universe = ['000300.XSHG']
context.base = '000300.XSHG'

"""策略主體"""
def handle(context, order):
    stock = context.universe[0]
    current_date = trade.context.current_dt
    kdj_day = get_kdj(stock, 30, current_date, '1d')

    k1 = kdj_day[0][-1]
    d1 = kdj_day[1][-1]
    j1 = kdj_day[2][-1]

    k2 = kdj_day[0][-2-1]
    d2 = kdj_day[1][-2-1]
    j2 = kdj_day[2][-2-1]

    close = get_price(security=stock, 
                      end_date=context.current_dt,
                      frequency='daily', 
                      fields=None, 
                      skip_paused=False, 
                      fq='pre',
                      count=20)['close']

    if k2 < d2 and k1 > d1:
        if stock in context.position.keys():
            return
        order.buy(stock, close[-1], context.cash // close[-1])
    elif k2 > d2 and k1 < d1:
        if stock not in context.position.keys():
            return
        order.sell(stock, close[-1], context.position[stock]['count'])

"""執行策略"""
trade.trade(handle, show=True, log=True)
End Time : 2019-03-10 16:11:04.901546, Elapsed Time: 0:00:20.362267
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章