用DataFrame作為容器分析市場行情指標

張國平發表於2019-03-17

 

----------------------------------------------4/24/2019--------------------------------------------------------------------

1. 新增方法addResultBar,可以在輸入引數中定義需要對比的的範圍,主要當前close和以後close的上漲下跌,和差值。

2. 新增方法resultOutput,根據對比值,輸出檢查點之後的走勢,支援匯出csv分析。

3. 修復一些比較機械的寫法

新的程式碼請下面Github

https://github.com/BillyZhangGuoping/MarketDataAnaylzerbyDataFrame

--------------------------------------------------------------------------------------------------------------------------------------------------

之前在看一篇《基於阻力支撐相對強度(RSRS)的市場擇時》(連結   https://mp.weixin.qq.com/s/LehwGXe_6JFZEZ8ekC4dCg)

 嘗試做為指標用在期貨量化交易,效果不怎麼理想。不過作者用DataFrame作為容器來分析指標,根據行情資料,分析指標效果,並進行驗證讓我學到不少。之前做量化交易策略設計時候只是靠第三方平臺或者交易軟體來驗證,很不專業。


就嘗試著用DataFrame作為容器分析市場行情指標,比如MACD,KDJ,CCI等等行情指標效用。這些行情指標,都可以從金融交易常用talib庫獲得。調出這樣指標,結合行情資料分析,用DataFrame做為容器,充分利用python的資料分析和圖片功能。

 

借花獻佛,東抄西抄,做了一個小tool和示例程式碼。

  1. 定義了一個類DataAnalyzer初始化的時候需要輸入生成csv檔案匯出資料夾地址,和資料格式

    1. 方法db2df,輸入vnpy使用Mongodb行情資料庫資訊和讀取品種資訊collection,程式會讀取指定品種的開始時間到結束時間段的一分鐘k線資料;按照初始化格式返回生成DataFrame供分析;如果expeort2csv為True的話,會生成一個csv檔案到指定地址.

    2. 方法csv2df,輸入指定路徑的csv行情檔案;程式讀取csv檔案;按照格式返回生成DataFrame供分析;如果expeort2csv為True的話,會生成一個csv檔案到指定地址。程式把匯入的字串轉換datetime格式,此時可能會有warning資訊。

    3. 方法df2Barmin,輸入DataFrame格式1分鐘行情資料,和指定輸出的多分鐘k線,程式整合出對應多分鐘k線資料。比如輸出1分鐘行情資料,要求輸出5分鐘k先資料;程式輸出5分鐘K線資訊DataFrame供分析。這裡有點地方要注意,如果資料中一天開始第一個bar是9點,那麼crossmin為1;  如果第一個是9點1分,此處為0。如果expeort2csv為True的話,會生成一個csv檔案到指定地址。

    4. 方法dfcci,其實是一個示例方法,輸入DataFrame格式分鐘行情資料,此處可以是1分鐘也可以是多分鐘的,和引數cciWindows;程式呼叫talib的cci方法,進行計算。返回帶有新的一列cci資料的DataFrame。用來分析。如果expeort2csv為True的話,會生成一個csv檔案到指定地址。開啟就是這樣一個東西。其他talib方法,其實呼叫原理差不多

      用DataFrame作為容器分析市場行情指標

  2. 通過上面的類,可以獲得一個帶有指標資料的DataFrame,後面就可以對這個進行分析,後面是一系列演示分析,其實DataFrame對應的分析工具很多多。

    1. 通過類的方法,讀取一個rb1905行情資料,按照聚合出5分鐘K線,在按照cci週期為15條K線計算cci值

    2. 畫出cci的柱狀分佈圖,CCI(Commodity       Channel       lndex)順勢指標是測量股價是否已超出常態分佈範圍的一個指數,波動於正無限大和負無限小之間。如下圖x軸是cci值,y軸是出現次數。從圖中可以看出cci資料是兩個正太分佈疊加,波峰在-80和+80兩個值,正負200之後,cci出現就變的很少,此時可以用DataFrame的數字分析功能找到更多資料。

      用DataFrame作為容器分析市場行情指標

    3. 計算每個時間點的當前價格,和之後第5根K線結束價格差,和cci的值做成散點圖,看看cci值和價格波動是否有聯絡。如下圖,圖象上看並沒有上面關聯。

      用DataFrame作為容器分析市場行情指標

    4. cci值在正負(100-200)區間,和(200-300)區間算是出現比較少,計算在這個區間出現時,之後第2,第4,和第6根K線結束價格增多還是減少概率。從下圖資料來看,似乎在(100,200)區間,第2個k線上漲概率大點點,但是也說明不了什麼。


    

 

原始碼如下,也可以去我的github去下載帶測試行情資料的:

https://github.com/BillyZhangGuoping/MarketDataAnaylzerbyDataFrame

# encoding: UTF-8
from pymongo import MongoClient, ASCENDING
import pandas as pd
import numpy as np
from datetime import datetime
import talib
import matplotlib.pyplot as plt
import scipy.stats as scs
class DataAnalyzer(object):
    def __init__(self, exportpath="C:\Project\\", datformat=['datetime', 'high', 'low', 'open', 'close','volume']):
        self.mongohost = None
        self.mongoport = None
        self.db = None
        self.collection = None
        self.df = pd.DataFrame()
        self.exportpath = exportpath
        self.datformat = datformat
    def db2df(self, db, collection, start, end, mongohost="localhost", mongoport=27017, export2csv=True):
        """讀取MongoDB資料庫行情記錄,輸出到Dataframe中"""
        self.mongohost = mongohost
        self.mongoport = mongoport
        self.db = db
        self.collection = collection
        dbClient = MongoClient(self.mongohost, self.mongoport, connectTimeoutMS=500)
        db = dbClient[self.db]
        cursor = db[self.collection].find({'datetime': {'$gte': start}, 'datetime': {'$lt': end}}).sort("datetime",
                                                                                                        ASCENDING)
        self.df = pd.DataFrame(list(cursor))
        self.df = self.df[self.datformat]
        self.df = self.df.reset_index(drop=True)
        path = self.exportpath + self.collection + ".csv"
        if export2csv == True:
            self.df.to_csv(path, index=True, header=True)
        return self.df
    def csv2df(self, csvpath, dataname="csv_data", export2csv=True):
        """讀取csv行情資料,輸入到Dataframe中"""
        csv_df = pd.read_csv(csvpath)
        self.df = csv_df[self.datformat]
        self.df["datetime"] = pd.to_datetime(self.df['datetime'])
        # self.df["high"] = self.df['high'].astype(float)
        # self.df["low"] = self.df['low'].astype(float)
        # self.df["open"] = self.df['open'].astype(float)
        # self.df["close"] = self.df['close'].astype(float)
        # self.df["volume"] = self.df['volume'].astype(int)
        self.df = self.df.reset_index(drop=True)
        path = self.exportpath + dataname + ".csv"
        if export2csv == True:
            self.df.to_csv(path, index=True, header=True)
        return self.df
    def df2Barmin(self, inputdf, barmins, crossmin=1, export2csv=True):
        """輸入分鐘k線dataframe資料,合併多多種資料,例如三分鐘/5分鐘等,如果開始時間是9點1分,crossmin = 0;如果是9點1分,crossmin為1"""
        dfbarmin = pd.DataFrame()
        highBarMin = 0
        lowBarMin = 0
        openBarMin = 0
        volumeBarmin = 0
        datetime = 0
        for i in range(0, len(inputdf) - 1):
            bar = inputdf.iloc[i, :].to_dict()
            if openBarMin == 0:
                openBarmin = bar["open"]
            if highBarMin == 0:
                highBarMin = bar["high"]
            else:
                highBarMin = max(bar["high"], highBarMin)
            if lowBarMin == 0:
                lowBarMin = bar["low"]
            else:
                lowBarMin = min(bar["low"], lowBarMin)
            closeBarMin = bar["close"]
            datetime = bar["datetime"]
            volumeBarmin += int(bar["volume"])
            # X分鐘已經走完
            if not (bar["datetime"].minute + crossmin) % barmins:  # 可以用X整除
                # 生成上一X分鐘K線的時間戳
                barMin = {'datetime': datetime, 'high': highBarMin, 'low': lowBarMin, 'open': openBarmin,
                          'close': closeBarMin, 'volume' : volumeBarmin}
                dfbarmin = dfbarmin.append(barMin, ignore_index=True)
                highBarMin = 0
                lowBarMin = 0
                openBarMin = 0
                volumeBarmin = 0
        if export2csv == True:
            dfbarmin.to_csv(self.exportpath + "bar" + str(barmins) + ".csv", index=True, header=True)
        return dfbarmin
    def dfcci(self, inputdf, n, export2csv=True):
        """呼叫talib方法計算CCI指標,寫入到df並輸出"""
        dfcci = inputdf
        dfcci["cci"] = None
        for i in range(n, len(inputdf)):
            df_ne = inputdf.loc[i - n + 1:i, :]
            cci = talib.CCI(np.array(df_ne["high"]), np.array(df_ne["low"]), np.array(df_ne["close"]), n)
            dfcci.loc[i, "cci"] = cci[-1]
        dfcci = dfcci.fillna(0)
        dfcci = dfcci.replace(np.inf, 0)
        if export2csv == True:
            dfcci.to_csv(self.exportpath + "dfcci" + ".csv", index=True, header=True)
        return dfcci
if __name__ == '__main__':
    DA = DataAnalyzer()
    #資料庫匯入
    # start = datetime(year=2019, month=3, day=1, hour=0, minute=0, second=0, microsecond=0)
    # end = datetime.today()
    # df = DA.db2df(db="VnTrader_1Min_Db", collection="rb1905", start = start, end = end)
    #csv匯入
    df = DA.csv2df("rb1905.csv")
    df10min = DA.df2Barmin(df,5)
    dfaftercci = DA.dfcci(df10min, 15)
    dfaftercci = dfaftercci.loc[15:,:]
    dfaftercci = dfaftercci.reset_index(drop=True)
    #######################################分析cci分佈########################################
    plt.figure(figsize=(15,5))
    plt.hist(dfaftercci['cci'],bins=100,histtype='bar',align='mid',orientation='vertical',color='r')
    plt.show()
    sta = scs.describe(dfaftercci.cci)
    stew = sta[4]
    kurtosis = sta[5]
    print('cci的偏度:%s' % (stew))
    print('cci的峰度:%s' % (kurtosis))
    #######cci在(100 - 200),(200 -300)後的第2根,第4根,第6根的價格走勢######################
    dfaftercci["next2BarClose"] = None
    dfaftercci["next4BarClose"] = None
    dfaftercci["next6BarClose"] = None
    dfaftercci["next5BarCloseMakrup"] = None
    for i in range(1, len(dfaftercci)-6):
        if dfaftercci.loc[i,"close"] > dfaftercci.loc[i+2,"close"]:
            dfaftercci.loc[i,"next2BarClose"] = -1
        else:
            dfaftercci.loc[i, "next2BarClose"] =1
        if dfaftercci.loc[i,"close"] > dfaftercci.loc[i+4,"close"]:
            dfaftercci.loc[i, "next4BarClose"] = -1
        else:
            dfaftercci.loc[i, "next4BarClose"] = 1
        if dfaftercci.loc[i,"close"] > dfaftercci.loc[i+6,"close"]:
            dfaftercci.loc[i, "next6BarClose"] = -1
        else:
            dfaftercci.loc[i, "next6BarClose"] = 1
        #######計算######################
        dfaftercci.loc[i,"next5BarCloseMakrup"] = dfaftercci.loc[i+5,"close"] - dfaftercci.loc[i,"close"]
    dfaftercci = dfaftercci.fillna(0)
    plt.figure(figsize=(15, 3))
    plt.scatter(dfaftercci["cci"], dfaftercci["next5BarCloseMakrup"])
    plt.show()
    for cciValue in [100,200]:
        de_anaylsis = dfaftercci.loc[(dfaftercci["cci"]>= cciValue)& (dfaftercci["cci"]< cciValue + 100)]
        percebtage = de_anaylsis[de_anaylsis["next2BarClose"]>0]["next2BarClose"].count()*100.000/de_anaylsis['cci'].count()
        print('在cci 區間(%s , %s) 時候,第二根K線結束價格上漲概率為 %s%%' %(cciValue,cciValue + 100,percebtage))
        percebtage = de_anaylsis[de_anaylsis["next2BarClose"]<0]["next2BarClose"].count()*100.000/de_anaylsis['cci'].count()
        print('在cci 區間-(%s , %s) 時候,第二根K線結束價格下跌概率為 %s%%' %(cciValue,cciValue + 100,percebtage))
        percebtage = de_anaylsis[de_anaylsis["next4BarClose"] > 0]["next2BarClose"].count() * 100.000 / de_anaylsis[
            'cci'].count()
        print('在cci 區間(%s , %s) 時候,第四根K線結束價格上漲概率為 %s%%' % (cciValue, cciValue + 100, percebtage))
        percebtage = de_anaylsis[de_anaylsis["next4BarClose"] < 0]["next2BarClose"].count() * 100.000 / de_anaylsis[
            'cci'].count()
        print('在cci 區間-(%s , %s) 時候,第四根K線結束價格下跌概率為 %s%%' % (cciValue, cciValue + 100, percebtage))
        percebtage = de_anaylsis[de_anaylsis["next6BarClose"] > 0]["next2BarClose"].count() * 100.000 / de_anaylsis[
            'cci'].count()
        print('在cci 區間(%s , %s) 時候,第六根K線結束價格上漲概率為 %s%%' % (cciValue, cciValue + 100, percebtage))
        percebtage = de_anaylsis[de_anaylsis["next6BarClose"] < 0]["next2BarClose"].count() * 100.000 / de_anaylsis[
            'cci'].count()
        print('在cci 區間-(%s , %s) 時候,第六根K線結束價格下跌概率為 %s%%' % (cciValue, cciValue + 100, percebtage))

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22259926/viewspace-2638612/,如需轉載,請註明出處,否則將追究法律責任。

相關文章