技術メモ

役に立てる技術的な何か、時々自分用の覚書。幅広く色々なことに興味があります。

pythonで為替データを取ってきて移動平均、ボリンジャーバンド、ゴールデンクロス、デッドクロスを可視化

pythonで為替データを分析したり可視化してみたいと考えた。
今回は、リアルタイムでドル円相場を取ってきてローソク足をプロットし、その上に移動平均ボラティリティゴールデンクロスデッドクロスを可視化してみるというところまでやってみる。

データを取ってくる

まずはデータを取ってこないといけない。
以前はCSVファイルを取ってこれるサイトを紹介したけれど、やっぱりリアルタイムでもデータを取ってきたい。(為替の分足CSVデータが無料でダウンロードできるサイト - 技術メモ
そこで今回はOANDAのAPIを使うことにした。
調べた限りOANDAだけが無料でリアルタイムのデータを取れるAPIを出してくれているらしいからだ。
OANDAの登録からキーの取得までは色々なサイトで確認してほしい。

pythonでは、oandapyV20というラッパーを使えばうまく取ってこられるらしい。
The oandapyV20 REST-V20 API wrapper documentation — OANDA REST V20 API Wrapper 0.6.3 documentation

ひとまずサンプルコードを動かしてみる。
コードは下の参考サイトにも載せた ここ を参考にした。

必要なライブラリがなければインストールしておく

pip install pandas
pip install matplotlib
pip install seaborn
pip install oandapyV20

今回はデータの取得と可視化を別のプログラムで書いたのでいったん”candle.csv”としてCSV形式で保存することにした。
account_tokenには自分で取得したアクセストークンを入れてほしい。

import datetime
import pandas
from oandapyV20 import API
import oandapyV20.endpoints.instruments as oandapy

start        = datetime.datetime(year=2018,month=5,day=1)
minutes      = 150 # 150分取得
start        = start.strftime("%Y-%m-%dT%H:%M:00.000000Z")
access_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
api          = API(access_token = access_token, environment="practice")
request      = oandapy.InstrumentsCandles(instrument = "USD_JPY",
               params = { "alignmentTimezone": "Japan", "from": start, "count": minutes, "granularity": "M1" })
api.request(request)

filename = "candle.csv"
candle = pandas.DataFrame.from_dict([ row['mid'] for row in request.response['candles'] ])
candle['time'] = [ row['time'] for row in request.response['candles'] ]
candle.to_csv(filename)

土日に動かしていたので日付は固定してしまっているが、スタート時刻を変えればリアルタイムでも動かせる。
(*土日は為替相場が閉まってるからデータが取れない!!!)

移動平均線、ボリバンを可視化する

import pandas
import seaborn
import matplotlib.pyplot as plt
from matplotlib.finance import candlestick2_ohlc as plt_candle
seaborn.set_style("whitegrid")

# csvを読み込む
candle = pandas.read_csv('candle.csv')

# 移動平均とボラティリティを求める
window_size  = 5 #5分移動平均を求める
avg_move     = pandas.Series.rolling(candle.c, window = window_size).mean().dropna().reset_index(drop = True)
sigma        = pandas.Series.rolling(candle.c, window = window_size).std(ddof = 0).dropna().reset_index(drop = True)
sigma_plus1  = avg_move + sigma
sigma_plus2  = avg_move + sigma * 2
sigma_plus3  = avg_move + sigma * 3
sigma_minus1 = avg_move - sigma
sigma_minus2 = avg_move - sigma * 2
sigma_minus3 = avg_move - sigma * 3

candle = candle[window_size:].reset_index(drop = True)

# X軸の見た目を整える
# 時間だけを切り出すために先頭からの12文字目から取るようにしている
xticks_number = 15 #15分刻みに目盛りを書く
xticks_index = range(0,len(candle), xticks_number)
xticks_date = [candle.time.values[i][11:16] for i in xticks_index]

figure, ax = plt.subplots()
plt_candle( ax,
            opens = candle.o.values,
            highs = candle.h.values,
            lows = candle.l.values,
            closes = candle.c.values,
            width=0.6,
            colorup='#DC143C',
            colordown='#4169E1')
plt.plot(avg_move, color='#006400')
plt.plot(sigma_plus1, color='#3CB371')
plt.plot(sigma_plus2, color='#9ACD32')
plt.plot(sigma_plus3, color='#ADFF2F')
plt.plot(sigma_minus1, color='#3CB371')
plt.plot(sigma_minus2, color='#9ACD32')
plt.plot(sigma_minus3, color='#ADFF2F')
plt.xticks(xticks_index, xticks_date, rotation=80)
plt.show()

f:id:swdrsker:20180518012800p:plain

5分の移動平均を求めている。
移動平均線ボリンジャーバンドアルゴリズム的に簡単に言うと
それぞれ「過去N本分のローソク足終値の平均、標準偏差」のこと。
標準偏差は1σ、2σ、3σまで求めるのが普通だ。


ここがよくわからないかもしれない

candle = candle[window_size:].reset_index(drop = True)

これは、移動平均と実際のローソク足を合わせることをしている。
移動平均線は過去5分の平均を求めている事を意味するので、最初の4分は意味がないことになる。
5分の移動平均線に対しては4分ずらさないとローソク足が一致しないので、そもそもデータから取り除いてしまえということだ。

意外と手間取ったのが見た目に関してだった。
良い感じで15分毎くらいにX軸を出したかったがあんまり簡単にできる方法が見つからなかった。
xticksという関数を見つけて無理やり良い感じになるようにしたけれどもっといい方法があるかもしれない。
あと、seabornは素晴らしいのでとりあえず使っとけって感じはある。

ゴールデンクロスデッドクロスを可視化

import pandas as pd
import seaborn
import matplotlib.pyplot as plt
from matplotlib.finance import candlestick2_ohlc as plt_candle
seaborn.set_style("whitegrid")

# csvを読み込む
candle = pd.read_csv('candle.csv')

#移動平均を求める
small_window = 5 # 5分平均線を求める
big_window   = 20 # 20分平均線求める
sma5         = pd.Series.rolling(candle.c, window = small_window).mean()
sma20        = pd.Series.rolling(candle.c, window = big_window).mean()

candle = candle[ big_window: ].reset_index(drop=True)
sma5 = sma5[ big_window: ].reset_index(drop=True)
sma20 = sma20[ big_window: ].reset_index(drop=True)

#ゴールデンクロス、デッドクロスを見つける
cross  = sma5 > sma20
golden = (cross != cross.shift(1)) & (cross == True)
dead   = (cross != cross.shift(1)) & (cross == False)

#ゴールデンクロス、デッドクロスの位置をリスト化する
index_g = [i-1 for i, x in enumerate(golden) if x == True]
index_d = [i-1 for i, x in enumerate(dead) if x == True]

# X軸の見た目を整える
# 時間だけを切り出すために先頭からの12文字目から取るようにしている
xticks_number = 15 #15分刻みに目盛りを書く
xticks_index = range(0,len(candle), xticks_number)
xticks_date = [candle.time.values[i][11:16] for i in xticks_index]

figure, ax = plt.subplots()
plt_candle( ax,
            opens = candle.o.values,
            highs = candle.h.values,
            lows = candle.l.values,
            closes = candle.c.values,
            width=0.6,
            colorup='#DC143C',
            colordown='#4169E1')
plt.plot(sma5, color='greenyellow', label='sma5')
plt.plot(sma20, color='darkgreen', label='sma20')
plt.scatter(index_g, sma20[index_g], color='red', s=500, label="golden cross")
plt.scatter(index_d, sma20[index_d], color='blue', s=500, label="dead cross")
plt.xticks(xticks_index, xticks_date, rotation=80)
plt.legend()
plt.show()

f:id:swdrsker:20180518013058p:plain

ゴールデンクロスデッドクロスは5分と20分の移動平均に関するクロスを計算するようにした。
ここでは20分移動平均線を5分移動平均線が下から交差すればゴールデンクロス、上から交差すればデッドクロス、ということにしている。

注意しないといけないことは、こちらは20分の移動平均を使っていることだ。
つまりローソク足に関しては最初の19分、5分の移動平均線に関しては最初の14分が不要ということになる。
それがこの部分にあたる。

candle = candle[ big_window: ].reset_index(drop=True)
sma5 = sma5[ big_window: ].reset_index(drop=True)
sma20 = sma20[ big_window: ].reset_index(drop=True)

どうやらゴールデンクロスデッドクロスについて調べてみると

長期移動平均線が上向きで短期移動平均が長期移動平均を下から上へクロスする場合、買い。(ゴールデンクロス
長期移動平均線が下向きで短期移動平均が長期移動平均を上から下へクロスする場合、売り。(デッドクロス
引用: http://fx.kakaku.com/fx/articleview/?no=21

と書かれてるところもあり、これに従うならもうすこし手を加える必要があるかもしれない。


OANDAのAPIは結構便利そうだ。
課金(口座に25万円以上入金)さえすればトレードに関するリクエストなんかも送れるらしく、リアルタイムで分析しながらシステムトレードなんかもできるかもしれない。
完全自動売買のプログラムによる不労所得生活もきっと夢じゃない。

Pythonでコマンドライン引数を渡す方法3種類

Pythonコマンドライン引数を渡す方法は知る限り下記の3種類ある。
1. sys.argv
2. argparser
3. docopt

このうち、主に上の2つを紹介する。

sys.argv

最も簡単な方法。
コマンドラインの引数を配列のようにして扱う。

sample

import sys

print('script name : %s'%sys.argv[0])
print(sys.argv[1])
$ python parsers.py hello
script name : parsers.py
hello

使い方

sys.argsに配列としてコマンドライン引数が入っている。0番目はプログラムの名前に当たるので、1番目以降を引数として使うことになる。

argparser

sys.argvでは引数の個数も決めておかないといけないし順番もバラバラではいけない。
使い方がわからなくなったとしたら、ソースを読むしかない。
これに対してargparserではシェルのコマンドのように"--help"や"-h"を引数にすることでヘルプを表示させることができる。
人に使ってもらうようなプログラムや大規模なプログラムを書くときはargparserを使うのが一番良いと思う。

sample

import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int,
                    nargs='+',help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                    const=sum, default=max,help='sum the integers (default: find the max)')
parser.add_argument('--display',action='store_true')

args = parser.parse_args()
if(args.display):
    print('result :')
print(args.accumulate(args.integers))
$ python parsers.py 1 2 3 --display
result :
3

$ python parsers.py 1 2 3 --sum
6

$ python parsers.py -h
usage: parsers.py [-h] [--sum] [--display] N [N ...]

Process some integers.

positional arguments:
  N           an integer for the accumulator

optional arguments:
  -h, --help  show this help message and exit
  --sum       sum the integers (default: find the max)
  --display

使い方

大まかな使い方としては
1.パーサーを作る
2.引数を追加する
3.引数を解析する
という順番になっている。
詳しくは下のリンク先のもとのソースを見てもらうとして、
引数を追加するadd_parser()の引数だけ示しておく。

name または flags - 名前か、あるいはオプション文字列のリスト (例: foo や -f, --foo)。
action - コマンドラインにこの引数があったときのアクション。
nargs - 受け取るべきコマンドライン引数の数。
const - 一部の action と nargs の組み合わせで利用される定数。
default - コマンドラインに引数がなかった場合に生成される値。
type - コマンドライン引数が変換されるべき型。
choices - 引数として許される値のコンテナー。
required - コマンドラインオプションが省略可能かどうか (オプション引数のみ)。
help - 引数が何なのかを示す簡潔な説明。
metavar - 使用法メッセージの中で使われる引数の名前。
dest - parse_args() が返すオブジェクトに追加される属性名。

ASP, Saas, Paas, Iaas, Daasの具体例を挙げてみる。活用方法など。

クラウドの分類として用いられるSaas…etcなどの分類、言葉だけ聞くとあまりピンとこない。
実例を挙げることでイメージしやすくしてみた。
f:id:swdrsker:20180202042259p:plain*1

ASP, Saas

ASPはアプリケーションソフトの機能をネットワーク経由で顧客にサービスとして提供することであり、それを行っている事業者である。通常、利用者はブラウザソフトなどを使用してインターネットなどのネットワークを経由し、遠隔地からASPのサーバにアクセスすることで、そのサーバ内に格納された各種アプリケーションソフトの機能をサービスの形で利用する。
wikipedia: アプリケーションサービスプロバイダ

SaaS(サース、Software as a Service)は、必要な機能を必要な分だけサービスとして利用できるようにしたソフトウェア(主にアプリケーションソフトウェア)もしくはその提供形態のこと。一般にはインターネット経由で必要な機能を利用する仕組みで、シングルシステム・マルチテナント方式になっているものを指す
wikipedia: Saas

ASPSaasって何が違う?

説明を読むと、ん?何が違うの?って感じが、厳密な違いはないらしい。
ASPは事業者やビジネスモデルとしての意味合いが強く、Saasはサービスにフォーカスした言葉というニュアンスの違いだという。

具体例

Webブラウザ上で使うサービスは大体(全て?)Saasに当てはまる。

Paas

PaaSでは、ソフトウェアを構築および稼動させるための土台となるプラットフォームを、インターネット経由のサービスとして提供する。開発者は、プラットフォーム上で構築したサービスを自分の顧客に提供することができる。 具体的には、インフラ、DBMSユーザインタフェースなどのシステム開発手段となるツールや、開発したシステムを運用するための環境をインターネットを通じて「サービス」として提供し、月額使用料などの形で収入を得る事業モデルである
wikipedia: Paas

Iaas (Haas)

IaaS(Infrastructure as a Service の略。インターネットを利用したコンピュータの利用形態である。IaaSでは、コンピュータシステムを構築および稼動させるための基盤(仮想マシンやネットワークなどのインフラ)そのものを、インターネット経由のサービスとして提供する。
wikipedia: Iaas

Daas

DaaS は、Desktop as a Serviceの略で、その言葉のとおり個人用のデスクトップ環境をクラウド上に構築し、ネットワーク越しにその環境を呼び出して利用することを提供するサービスです。基本ソフトをはじめ全てのソフトやデータがネットワーク上のサーバーにあります。ユーザの端末は画面を表示する機能とキーボードなど操作に必要な機能だけあればよく、OSやアプリケーションソフトなどはすべてサーバ上で動作します。
DaaS(Desktop as a Service) | IoT

活用方法など【中級者以上向け】

この記事は面白い。

特に最近は人工知能ブームで機械学習や統計解析が盛んにおこなわれているが、その中で使うIoTでリアルタイムなデータを取ってきたりGPUAPIなんかを使いたい時にIaasやPaasを使うようだ。
データの管理やプログラムだけに集中したい時に重宝される。
経験上少し昔はそういった分析業務におけるクラウドAWS一強だった感じだが、Azureもそれなりに使われているらしい。