【Python】【トラリピ】トラップ範囲をmatplotlibで可視化する(クロス円単一通貨ペアver)

Python

トラップ範囲を決める際、チャートを見ながら決めます。〇〇年間のチャートで中央値はいくらでmax,minはいくらなどを参考にします。

トラリピアプリでも確認できますが、トラリピ注文を入れてからです。入れる前はチャートと合わせて確認できません。

Excelを使ってチャートと一緒に書いた事はありますが、毎回最新の為替データを持ってきて描画しなければならないのがイマイチ

Googleスプレッドシートも使いました。これは為替データを拾う関数があるのでExcelよりは便利でしたが、データ数の関係でシートが重い。値をいろいろ変えて確認するにはこの重さがイマイチ

というわけで、Pythonとmatplotlibで書いてみました。

プログラムの大半は、以前投稿したこちらの記事↓と同じですが、グラフ描画機能を追加したことと、1通貨ペア(クロス円)としたところが違います。(複数通貨ペアのままだとグラフが多すぎてカオスだったので1通貨ペアにしました)

プログラム

# -*- coding: utf-8 -*-
# onepare-corss.py
"""
決め事
ロスカットレートはトラリピ範囲外にすること
理由は、必要資金が範囲リミット時よりもロスカットレート時のほうが多く必要という見方をしているため
そんなことに囚われず、常に多い方をしっかり見れていれば上記ルールは不要だが
いつも注視してるなんて無理

df0 : FREDから取得したデータ用
df1 : トラップ
df : 表示用
"""

import numpy as np
import pandas as pd
import pandas_datareader.data as pdr
import datetime as dt
import matplotlib.pyplot as plt
from matplotlib import dates as mdates
from dateutil.relativedelta import relativedelta # timedeltaはyearsの指定ができないのでdateutilを使う
from matplotlib.text import OffsetFrom

# 計算したいペア 任意の名前
showpare = 'JPYAUD'

# レート取得範囲設定
deltayear = 10 # n年前までのデータを取得する
dateend = dt.date.today() # 取得範囲のエンドは本日まで
datestart = dateend - relativedelta(years=deltayear) # 本日からn年前が取得範囲のスタート
tickerlist = ['DEXJPUS','DEXUSAL'] # 取得するtickerのlist 豪ドル/円が欲しいので米ドル/円と米ドル/豪ドルを取得する(Fredには豪ドル/円は無いので計算する)
# FREDから取れるデータの例↓
# DEXJPUS : JPY/USD
# DEXUSAL : USD/AUD
# DEXUSNZ : USD/NZD
# DEXCAUS : CAD/USD

# DataReaderでFredからレートを取得しデータフレームdf0に格納
df0 = pdr.DataReader(tickerlist,'fred',datestart,dateend) # 日次データ

df0['JPYAUD'] = df0['DEXJPUS'] * df0['DEXUSAL'] # JPY/AUD算出
# 別の通貨ペア算出の例↓
# df0['JPY/NZD'] = df0['DEXJPUS'] * df0['DEXUSNZ'] # JPY/NZD算出
# df0['JPY/CAD'] = df0['DEXJPUS'] * (1 / df0['DEXCAUS']) # JPY/CAD算出
df0 = df0.resample('W').last() # 週末の値に変換(週足) # FREDは高頻度に更新しないようなので、週末の値を最新として考えちゃう

# 最終行のデータを取得
# つまり、最新で、currencydataに最も近い
# ilocで取得すると単一の値になる
JPYUSD = df0.iloc[-1]['DEXJPUS'] # JPYUSDの最終行の値を取得
USDAUD = df0.iloc[-1]['DEXUSAL'] # USDAUDの最終行の値を取得
SHOW = df0.iloc[-1][showpare] # 知りたい通貨ペア
print('Currency JPY/USD : '+ str(JPYUSD))
print('Currency USD/AUD : '+ str(USDAUD))
print('Currency ' + showpare + ' : ' + str(round(SHOW,2)))

# トラリピ範囲設定
pare = [showpare,showpare] #BUY,SELLの順番で記載する
start = [70.4,85.6] # 下限
end = [85.2,100.4] # 上限
pcs = [38,38] # 本数 buy,sellで本数を揃えないとプログラムがエラー
unit = 1000
losscutrate = [65,104]

# 空の配列を用意
spanstep = np.empty(len(pare))
suma = np.empty(len(pare))
sumb = np.empty(len(pare))
sumc = np.empty(len(pare))
sumd = np.empty(len(pare))
sume = np.empty(len(pare))
urikai = []
span = [] # spanを配列として定義

df1 = pd.DataFrame(span) # spanstep描画用

# トラップ計算
for i in range(len(pare)):
    span = np.linspace(start[i],end[i],pcs[i])
    df1[i] = span # iごとにspanをdf1に追加 span表示用

    spanstep[i] = span[1] - span[0]
    
    suma[i] = np.sum(span * unit * 0.04) # 必要証拠金
    sumb[i] = np.sum((span - start[i]) * unit) # 含み損(limit時)
    sumc[i] = np.sum((abs(span - losscutrate[i])) * unit) # 含み損(ロスカットレート時)
    sumd[i] = suma[i] + sumb[i] # 必要資金(limit時)
    sume[i] = suma[i] + sumc[i] # 必要資金(ロスカットレート時)
    if( losscutrate[i] <= min(span) ): # 売り買いどっち?
            urikai.append('買')
    else:
            urikai.append('売')

df = pd.DataFrame({
	'通貨':pare,
	'売買':urikai,
	'start':start,
	'end':end,
	'step':spanstep,
  'pcs':pcs,
	'losscutrate':losscutrate,
	# 'A必要証拠金':suma,
	# 'B含み損(limit時)':sumb,
	# 'C含み損(ロスカットレート時)':sumc,
	'D必要資金(limit時)':sumd, # A+B
	'E必要資金(ロスカット時)':sume # A+C
	})
df = df.round(3)

groupedcolumns = ['pcs','D必要資金(limit時)','E必要資金(ロスカット時)']
grouped2columns = ['D必要資金(limit時)','E必要資金(ロスカット時)']
grouped = df.groupby(['通貨','売買']).sum() # 通貨、売買のそれぞれの合計値
grouped2 = grouped.groupby('通貨').max() # 通貨ごとに最大値を出す(half&half用) それぞれの列のmaxなので行は合っていないので注意
print('全必要資金(limit時) : '+'{:,.0f}'.format(grouped2['D必要資金(limit時)'].sum())+' JPY') # 必要資金の合計を表示(全通貨)
print('全必要資金(ロスカット時) : '+'{:,.0f}'.format(grouped2['E必要資金(ロスカット時)'].sum())+' JPY') # 必要資金の合計を表示(全通貨)

# =====================
# csv出力
# =====================
# define file name
# /や:があるとエラーになる(oserror22)
savename =str(showpare)+'_'+'B'+ str(start[0])+'to'+str(end[0])+'_'+'S'+str(start[1])+'to'+str(end[1])+'_'+'pcs'+str(pcs[0])+'_'+'step'+str(round(spanstep[0],1))+'_'+str(deltayear)+'years'

# df.to_csv('onepare-cross-'+savename+'.csv')
# grouped.to_csv('onepare-cross-grouped-'+savename+'.csv',columns=groupedcolumns)
# grouped2.to_csv('onepare-cross-grouped2-'+savename+'.csv',columns=grouped2columns)
df1.to_csv('onepare-cross-trap-'+savename+'.csv')

# =====================
# graph描画設定
# =====================
fig = plt.figure(figsize=(6,6))
ax1 = fig.add_subplot(111)
plt.title(showpare +' Past '+str(deltayear)+' years data from FRED') # title

# x軸設定
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) # 年-月
ax1.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=8)) # 最大8個のラベルを設定

# ラベル設定
ax1.set_xlabel('DATE',rotation=0) # x軸のラベル
ax1.xaxis.set_tick_params(rotation=0) # ラベルを斜めにできる
ax1.set_ylabel(showpare) # y軸のラベル
ax1.grid(True) # grid表示

# メインデータ描画
ax1.plot(df0[showpare],alpha=0.2,color='blue')

# BUYロスカット描画(偶数)
ax1.hlines(losscutrate[0],datestart,dateend,'red',linestyle='dashed') # 線を引く
ax1.annotate(
        'BUY : '+str(losscutrate[0])+' : '+'{:,.0f}'.format(sume[0])+' JPY',
        xy=(dateend,losscutrate[0]),
        xycoords='data',
        xytext=(0,10),
        textcoords='offset points',
        color='red',
        horizontalalignment='right') # 値を表示

# SELLロスカット描画(奇数)
ax1.hlines(losscutrate[1],datestart,dateend,'red',linestyle='dashed') # 線を引く
ax1.annotate(
        'SELL : '+str(losscutrate[1])+' : '+'{:,.0f}'.format(sume[1])+' JPY',
        xy=(dateend,losscutrate[1]),
        xycoords = 'data',
        xytext = (0,-10),
        textcoords = 'offset points',
        color='red',
        horizontalalignment='right') # 値を表示

# BUYトラップ範囲描画
ax1.axhspan(start[0],end[0],alpha=0.3,color='coral')
ax1.hlines(df1[0].values,datestart,dateend,color='coral',alpha=0.5) # step線
ax1.annotate(
        str(start[0])+' : '+'{:,.0f}'.format(sumd[0])+' JPY',
        xy=(datestart,start[0]),
        xycoords='data',
        xytext=(20,20),
        textcoords='offset points',
        arrowprops=dict(arrowstyle='->',
        connectionstyle='angle,angleA=0,angleB=90,rad=10'),
        horizontalalignment='left',
        verticalalignment='bottom') # start値

ax1.annotate(
        str(end[0]),
        xy=(datestart,end[0]),
        xycoords='data',
        xytext=(20,-20),
        textcoords='offset points',
        arrowprops=dict(arrowstyle='->',
        connectionstyle='angle,angleA=0,angleB=90,rad=10'),
        horizontalalignment='left',
        verticalalignment='bottom') # end値

# SELLトラップ範囲描画
ax1.axhspan(start[1],end[1],alpha=0.3,color='deepskyblue')
ax1.hlines(df1[1].values,datestart,dateend,color='deepskyblue',alpha=0.5) # step線

ax1.annotate(
        str(start[1]),
        xy=(datestart,start[1]),
        xycoords='data',
        xytext=(20,20),
        textcoords='offset points',
        arrowprops=dict(arrowstyle='->',
        connectionstyle='angle,angleA=0,angleB=90,rad=10'),
        horizontalalignment='left',
        verticalalignment='bottom') # start値

ax1.annotate(
        str(end[1])+' : '+'{:,.0f}'.format(sumd[1])+' JPY',
        xy=(datestart,end[1]),
        xycoords='data',
        xytext=(20,-20),
        textcoords='offset points',
        arrowprops=dict(arrowstyle='->',
        connectionstyle='angle,angleA=0,angleB=90,rad=10'),
        horizontalalignment='left',
        verticalalignment='bottom') # end値

# max描画
maxxval = df0[showpare].idxmax()
maxyval = df0[showpare].max()
ax1.plot(maxxval,maxyval,marker='2',markersize=10,color='black')
ax1.annotate(' MAX : '+str(round(maxyval,1)),xy=(maxxval,maxyval))

# min描画
minxval = df0[showpare].idxmin()
minyval = df0[showpare].min()
ax1.plot(minxval,minyval,marker='2',markersize=10,color='black')
ax1.annotate(' MIN : '+str(round(minyval,1)),xy=(minxval,minyval))

# median描画
medval = (maxyval - minyval) / 2 + minyval
ax1.hlines(medval,datestart,dateend,linestyle='dotted',color='black')
ax1.annotate(
        'MED : '+'{:,.2f}'.format(medval),
        xy=(dateend,medval),
        color='black')
        
# Currency描画
ax1.hlines(SHOW,datestart,dateend,linestyle='dotted',color='blue')
ax1.annotate(' NOW : '+str(round(SHOW,1)),xy=(dateend,SHOW),color='blue')

# step,pcs描画
ax1.annotate(
        'step: '+str(round(spanstep[0],1)) + ' pcs: ' + str(pcs[0]),
        xy=(datestart,minyval),
        xycoords = 'data',
        xytext = (0,-15),
        textcoords = 'offset points')

plt.tight_layout() # ラベルが重ならないようにいい感じに調整する

plt.savefig('onepare-cross-'+savename+'.png',format='png',dpi=150) # グラフ保存

実行結果

例として以下で実行しています。

  • 通貨ペア:豪ドル円
  • プログラム実行日(本日)から10年前までのチャートを表示(deltayear)
  • トラリピの設定はプログラム参照

グラフ表示他、データフレームの内容をcsvで吐いています。

csv出力部分でコメントアウトしてある部分がありますので、適宜アンコメントしてもらえば、dfやgrouped,grouped2のcsvも吐けます。

ファイル名はプログラム中で設定した条件で決めているので、様々な条件で比較したいときに別名保存されるので便利です。(ファイル名が長いのが難点ですが・・・)

おしまい(^^)

タイトルとURLをコピーしました