【株式自動売買】移動平均線ペア間の平均利益率月間推移に関する相関を調べてみた話。

目次。

 

 

はじめに。

株式自動売買プログラム開発関連の文章は、以下のカテゴリーにまとめているので、興味のある方はどうぞ。

blog.sun-ek2.com

 

前回は、株式の流動性(出来高)が移動平均線ペアを使ったトレードに与える影響を調べてみた。

blog.sun-ek2.com

 

今回は、異なる移動平均線ペアを使ったときの平均利益率の月間推移に関する相関を調べてみたという話。

 

今、考えている株式売買のアルゴリズムは、複数の移動平均線ペアを使って、売買タイミングを決定するというもの。一つの移動平均線ペアだと、利益が出る局面もあるが、逆に損失ばかり出る局面もある。上手く複数の移動平均線ペアを選べば、ある局面で、とあるペアが損失を出しまくったとしても、別のペアが利益を出してくれて、市場がどのような状態になっても、トータルで安定的に黒字を出せるのではないかと考えた。

 

問題は、複数の移動平均線ペアの選び方。同じタイミングで利益を出して、同じタイミングで損失を出す移動平均線ペアを2組、選んでも意味がない。それは、1組の移動平均線ペアを使っているのと変わりがなく、一方のペアが損失を出しているときに他方は利益を出してくれない。

 

そのため、選んだ複数の移動平均線ペアの利益・損失が出るタイミングはできるだけ、ばらけていなければいけない。ばらけていれば、一方のペアが損失を出しているときに他方が利益を出してくれる可能性が高まる。

 

異なる移動平均線ペアを使ったときの平均利益率の月間推移に対する相関係数を調べてみた。相関係数が低いほど、利益・損失が出るタイミングが異なっている。今回の解析で、できるだけ相関係数が低い複数の移動平均線ペアを探し、それら複数のペアを今後のアルゴリズムに使っていきたい。

 

 

 

 

まずは前回と同様に。。。

前回、株式の流動性(出来高)を指標に4000銘柄を4つのグループ(各1000銘柄)に分けて、5年間・1銘柄あたりの平均利益率を調べてみた。そうすると、流動性(出来高)が3001位以下の銘柄をターゲットに売買を行っても、あまり利益が出ないということが分かった。

blog.sun-ek2.com

 

そのため、今回は、流動性(出来高)が3001位以下の利益が出ない銘柄を省き、3000銘柄(各750銘柄)を4つのグループに分けて解析を行った。

f:id:sun_ek2:20200424232403p:plain

 

前回のヒートマップのスケールバーの最高値は、0.25だったが、今回は0.3。前回同様、今回も流動性(出来高)は、高すぎても低すぎてもダメだということが分かる。

 

 

 

 

n日・m日の短期・長期移動平均線を使ったときの平均利益率の月間推移。

5年間・1銘柄あたりの平均利益率は、5年間のデータを全て足し合わせ、全銘柄数で割って平均を取っていたが、今回は、平均利益率を月単位で足し合わせ算出した。買い注文と売り注文が月をまたいだ場合、その損益は買い注文を行った月にまとめた。

 

結果は、こんな感じ。グラフの上にあるn-mは、n日・m日の短期・長期移動平均線を使って得られた結果ということを表している。

(ブログに投稿した後に気づいたのだが、グラフの画像が圧縮されてしまい、拡大したら文字が読めなくなっている。1段目のグラフの上部には、左から1-6、1-7、…1-30と書かれており、2段目のグラフの上部には、左から2-7、2-7、…2-30と書かれている。3段目以降も同様)

f:id:sun_ek2:20200424232451p:plain

 

各グラフの横軸は年月、縦軸が平均利益率。ギザギザがy軸の真ん中よりも上にあれば、利益が出ていて、下にあれば、損失が出ている。細かすぎて、このグラフから読み取れることはあまりないが、とりあえず次の相関解析に必要なデータは用意できた。

(2018年5月~2019年5月は、どんな移動平均線ペアを使ってもなかなか利益は出ないということは分かった)

 

 

 

 

相関解析。

結果は、以下の通り。横軸・縦軸は、上のグラフを一列に並べたものに対応している。

f:id:sun_ek2:20200424232634p:plain

 

全てのデータが移動平均という考え方に準拠しているせいか、データを月単位でまとめて、750銘柄の平均を取っているせいか、どの組み合わせでも相関係数は高かった。また、出来高で分けたグループ間であまり差異は見られなかった。

 

しかし、平均利益率月間推移の上三角グラフにおいて、左上(n、mともに小さい)、右上(nは小さく、mは大きい)、右下(n、mともに大きい)間の相関係数は、予想通り近傍に比べて小さくなるということが分かった。

 

 

 

 

ソースコード(プログラムコード)。

パソコンから見た方が見やすいかも。

import XXXXX #昔の記事を参照のこと。
import glob
import datetime
import re
import numpy as np
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rcParams
import scipy.stats as sts


storage_uri = 'YYYYY'
gl = glob.glob(storage_uri+'outputs\\stock_price_data\\day\\*.csv')


#stock_volume_ranking_codeは、『【株式自動売買】株式の流動性(出来高)が移動平均線ペアを使ったトレードに与える影響を調べてみた話。』を参照のこと。
profit_loss_list_all = []
for f in gl[:]:
    stock_code = f.replace(storage_uri+'outputs\\stock_price_data\\day\\', '')
    stock_code = re.sub('-.*', '', stock_code)

    if int(stock_code) in stock_volume_ranking_code[3000:]:
        print('3000位以下')
        continue
    if re.compile('-.csv').search(f):
        continue

    stock_data = XXXXX.prepare_data(f)
    DMAL_list = []
    for i in range(1, 31):
        DMAL_list.append(XXXXX.calc_nDayMovingAverageLine(stock_data,i))

    for short in range(1, 26):
        for long in range(short+5, 31):
            DMAL_short = DMAL_list[short-1]
            DMAL_long = DMAL_list[long-1]
            diff_DMAL = XXXXX.compare_nDayMovingAverageLines(DMAL_short, DMAL_long)
            buy_or_sell_list = XXXXX.find_intersections(diff_DMAL)
            evaluation, result = XXXXX.evaluate(buy_or_sell_list, stock_data)
            buying_timing = [0, 0]
            profit_loss_tmp = str(stock_code) + ',' + str(short) + ',' + str(long) + ','
            for i in range(len(evaluation.values)):
                tmp_eval =  evaluation.values[i][0]
                if tmp_eval < 0:
                    buying_timing = [i, tmp_eval]
                if tmp_eval > 0:
                    profit_loss_tmp += str(evaluation.index[buying_timing[0]]) + ',' + str((tmp_eval+buying_timing[1])/-buying_timing[1]) + ','
            with open(storage_uri + 'outputs\\profit_loss_list_all.txt', mode='a') as file_1:
                print(profit_loss_tmp[:-1], file=file_1)


profit_loss_all = None
with open(storage_uri + 'outputs\\profit_loss_list_all.txt',encoding="utf-8_sig") as f:
        profit_loss_all = [s.replace('\n','').split(',') for s in f.readlines()]


profit_loss_all_2 = [[], [], [], []]
for short in range(1, 26):
    for long in range(short+5, 31):
        print(short, long)
        for i in range(4):
            profit_loss_all_2[i].append([short, long])

        for profit_loss_ele in profit_loss_all:
            cl = -1
            if int(profit_loss_ele[0]) in stock_volume_ranking_code[:750]:
                cl = 0
            if int(profit_loss_ele[0]) in stock_volume_ranking_code[751:1500]:
                cl = 1
            if int(profit_loss_ele[0]) in stock_volume_ranking_code[1501:2250]:
                cl = 2
            if int(profit_loss_ele[0]) in stock_volume_ranking_code[2251:3000]:
                cl = 3
            if int(profit_loss_ele[1]) == short and int(profit_loss_ele[2]) == long:
                profit_loss_all_2[cl][-1].extend(profit_loss_ele[3:])


year_month_dict_init = {}
year_month_init = datetime.datetime(2015, 4, 1)
for i in range(100000):
    tmp = year_month_init + datetime.timedelta(weeks=4*i)
    year_month_dict_init[tmp.strftime('%Y%m')] = 0
    if tmp.strftime('%Y%m') == '202002':
        break


profit_loss_all_3 = [[], [], [], []]
for cl in range(4):
    for profit_loss_ele_2 in profit_loss_all_2[cl]:
        tmp = year_month_dict_init.copy()
        for i in range(int(len(profit_loss_ele_2[2:])/2)):
            if not(profit_loss_ele_2[2*(i+1)][:-2] in tmp.keys()):
                continue
            tmp[profit_loss_ele_2[2*(i+1)][:-2]] += float(profit_loss_ele_2[2*(i+1)+1])
        profit_loss_all_3[cl].append([profit_loss_ele_2[0], profit_loss_ele_2[1], tmp.copy()])
np.save(storage_uri + 'profit_loss_list_all2.npy', np.array(profit_loss_all_3))


number_of_stock_name = 750
year_month = [[], [], [], []]
vals = [[], [], [], []]
profit_loss_all_3 = np.load(storage_uri + 'profit_loss_list_all2.npy')
for k in range(4):
    for i in range(len(profit_loss_all_3[0])):
        year_month[k].append([datetime.datetime(int(j[:4]), int(j[4:6]), 1) for j in profit_loss_all_3[k][i][2].keys()])
        vals[k].append([j/number_of_stock_name for j in profit_loss_all_3[k][i][2].values()])


val_max = np.max(vals)
val_min = np.min(vals)
result_np = np.zeros((4, len(vals[0]), len(vals[0])))
short_max = 26
long_max = 31
index = []


for k in range(4):
    counter = 0
    for short in range(1, short_max):
        for long in range(short+5, long_max):
            plt.rcParams['figure.figsize'] = (2*short_max,2*long_max)
            ax = plt.subplot(long_max, short_max, (short-1)*(long_max-6)+long-5+short-1)
            ax.plot(year_month[k][counter], vals[k][counter], color='black')
            ax.set_title(str(short)+'-'+str(long), size = 10)
            if k == 0:
                index.append(str(short)+'-'+str(long))
            for counter2 in range(counter, len(vals[k])):
                result_np[k, counter, counter2] = sts.pearsonr(vals[k][counter], vals[k][counter2])[0]
            counter += 1
            plt.tick_params(labelbottom=False, labelleft=False, labelright=False)
            plt.ylim(-max(val_max, -val_min), max(val_max, -val_min))
            plt.subplots_adjust(hspace = 1)
    plt.subplots_adjust(left=0.1, right=0.95, bottom=0.1, top=0.95)
    if k == 0:
        plt.suptitle('①出来高:1位~750位 平均利益率の月間推移', fontsize=80)
        plt.savefig(storage_uri + 'outputs\\①出来高:1位~750位 平均利益率の月間推移.png')
    if k == 1:
        plt.suptitle('②出来高:751位~1500位 平均利益率の月間推移', fontsize=80)
        plt.savefig(storage_uri + 'outputs\\②出来高:751位~1500位 平均利益率の月間推移.png')
    if k == 2:
        plt.suptitle('③出来高:1501位~2250位 平均利益率の月間推移', fontsize=80)
        plt.savefig(storage_uri + 'outputs\\③出来高:1501位~2250位 平均利益率の月間推移.png')
    if k == 3:
        plt.suptitle('③出来高:2251位~3000位 平均利益率の月間推移', fontsize=80)
        plt.savefig(storage_uri + 'outputs\\③出来高:2251位~3000位 平均利益率の月間推移.png')
    plt.figure()


plt.figure(figsize=(20, 20))
for i in range(4):
    tmp = pd.DataFrame(data=result_np[i], index=index, columns=index)
    ax = plt.subplot(2,2,i+1)
    sns.heatmap(tmp, square=True)
    if i == 0:
        plt.title('①出来高:1位~750位', fontsize=24)
    if i == 1:
        plt.title('②出来高:751位~1500位', fontsize=24)
    if i == 2:
        plt.title('③出来高:1501位~2250位', fontsize=24)
    if i == 3:
        plt.title('③出来高:2251位~3000位', fontsize=24)

    plt.suptitle('移動平均線ペア間の平均利益率に関する相関行列', fontsize=36)
plt.savefig('移動平均線ペア間の平均利益率に関する相関行列')

 

 

まとめとか。

今回は、異なる移動平均線ペアを使ったときの平均利益率の月間推移に対する相関係数を調べてみた。前回の結果と今回の結果をもとに実際に自動売買で使う移動平均線ペアを決めていきたいと思う。

 

この解析は、月単位で行った。今後、少しターゲットを絞った後、日単位の平均利益率推移を使って相関係数を調べたい。そうすれば、もっとはっきり移動平均線ペア間での相関の高さが見れると思う。(今回もそれでやろうと思ったが、計算量が多すぎるので諦めた)

 

ブログランキング・にほんブログ村へ
にほんブログ村