%matplotlib inline
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
import matplotlib.pyplot as plt
import seaborn as sns
import requests
from bs4 import BeautifulSoup
qiitaで見かけた記事でみずほ銀行のデータを使ってたので自分も取得してみた
# レート取得
url = 'https://www.mizuhobank.co.jp/rate/market/csv/quote.csv'
df = pd.read_csv(url, header=2, index_col=0, parse_dates=True)
print(df.shape)
df.head(3)
df.dtypes
# float型の列だけにする
df = df.loc[:, df.dtypes==np.float64]
print(df.shape)
df.head(3)
# nanが混じってる列を除去
df.dropna(axis=1, inplace=True)
print(df.shape)
df.head(3)
上記のみずほ銀行のデータは対円レートなので(いや、よく確認してないけど)kuchart計算しやすいぞ
と思ってkuchartを計算
ここは遊び心をきかせてワンライナーで(´・ω・`)ノ
(lambda使いまくって無理やり感ありますが(^^;))
計算式はこちらの http://fxst24.blog.fc2.com/
「Ku-Chartの簡単な計算方法」のやり方がいい感じなので参考にさせてもらいました
ku = DataFrame((lambda arr:(lambda ret:(lambda ret,a:np.concatenate([np.subtract(ret,a),-a],axis=1))(ret,(ret.sum(axis=1)/(len(df.columns)+1))[:,np.newaxis]))(np.concatenate([[np.zeros(arr.shape[1])],np.log(arr[1:]/arr[:-1])])))(df.values),index=df.index,columns=list(df.columns)+['JPY'])
# プロット
KU_CLR = {'EUR':'red', 'GBP':'green', 'USD':'orange', 'JPY':'turquoise',
'AUD':'royalblue', 'NZD':'violet', 'CAD':'blueviolet', 'CHF':'gray'}
def ku2clr(df_or_col):
col = df_or_col
if isinstance(df_or_col, DataFrame): col = df_or_col.columns
return [KU_CLR[s] if s in KU_CLR else 'k' for s in col]
ku.cumsum().plot(figsize=(15,10), lw=1, color=ku2clr(ku), legend=None)
# ↑ のだとちょっと見にくいので8通貨だけ表示してみます
major_symbols = list(KU_CLR.keys())
ku8 = ku[major_symbols]
ku8.cumsum().plot(figsize=(15,5), lw=1, color=ku2clr(major_symbols), legend=None)
plt.legend(major_symbols)
# 年ごとに
gb = ku8.groupby(ku8.index.year)
plt.figure(figsize=(15,5))
ax = plt.subplot()
for k,v in gb:
v.cumsum().plot(lw=1, color=ku2clr(v), ax=ax, legend=None)
plt.axvline(v.index[0], lw=0.5, c='k', ls=':')
plt.legend(ku8)
このgroupbyオブジェクトをそのままforで回せるって最近知りました 便利(*´・ω・`*)
ワンライナーはさておき、
たいていはドルストレートから計算すると思うのでこんな感じにしました
(一応、基準となる通貨が揃っていればドルストじゃなくても計算できるようにはなっている)
※さっきのみずほ銀行のデータだと引数を calc_ku(df, basis='JPY') て感じで指定
def calc_ku(df, basis='USD'):
ku_symbols = [s.replace(basis, '') for s in df.columns] + [basis]
mask_symbols_mul = np.array([(1 if s[:3]!=basis else -1) for s in df.columns])
arr = df.values
ret = np.concatenate([[np.zeros(arr.shape[1])], np.log(arr[1:]/arr[:-1])])
a = ((ret*mask_symbols_mul).sum(axis=1) / (arr.shape[1]+1))[:,np.newaxis]
ku_arr = np.concatenate([np.subtract(ret*mask_symbols_mul, a), -a], axis=1)
return DataFrame(ku_arr, index=df.index, columns=ku_symbols)
# こんな感じ対ドルのデータフレームがあったとして (手元のMT4から読み込んだデータです)
print(df2.shape)
df2.head()
kuh1 = calc_ku(df2)
print(kuh1.shape)
kuh1.cumsum().plot(figsize=(15,5), lw=1, color=ku2clr(kuh1))
OK(´・ω・`)
みずほ銀行のデータを取得してみて、
ほかにログインとか認証とかしなくても取得できる為替のデータってなにがあるかなぁと調べてたら、
oandaのヒストリカルデータはapiの認証しなくても取得できることに気づいた(´・ω・`)
# 取り扱ってるペア
soup = BeautifulSoup(requests.get('https://www.oanda.jp/service/fxtrade.php').content, 'lxml')
oanda_symbols = [tr.select('td')[0].text.replace('/','')
for tr in soup.select('.tb-service tbody tr')
if tr.select('td')]
print(oanda_symbols)
# M1 USDJPY を3本取得してみる
res = requests.get('https://api-fxpractice.oanda.com/v1/candles',
params={'granularity':'M1', 'count':3, 'instrument':'USD_JPY'})
DataFrame(res.json()['candles']).head()
ふむふむ(´・ω・`)
def oanda_ohlc(symbol, tf='M1', count=10, start=None, end=None,
unixtime=True, alignmentTimezone='America/New_York',
adjhour=9, timeout=10, **kw):
symbol = symbol if '_' in symbol else symbol[:3]+'_'+symbol[3:]
headers = {'X-Accept-Datetime-Format': 'unix'} if unixtime else {}
params = {'granularity': tf, 'count': count, 'instrument': symbol}
params.update(**kw)
adj = lambda x: pd.to_datetime(x)-pd.offsets.Hour(adjhour)
if unixtime:
f = lambda x: adj(x).to_datetime64().astype(np.int64)
to_dt = lambda df: pd.to_datetime(df['time'], unit='us')+pd.offsets.Hour(adjhour)
else:
f = lambda x: adj(x).strftime('%Y-%m-%dT%H:%MZ')
to_dt = lambda df: pd.to_datetime(df['time'])+pd.offsets.Hour(adjhour)
if start: params['start'] = f(start)
if end: params['end'] = f(end)
if start or end: params.pop('count')
# url = 'https://api-fxtrade.oanda.com/v1/candles'
url = 'https://api-fxpractice.oanda.com/v1/candles'
res = requests.get(url, headers=headers, params=params, timeout=timeout)
if res.status_code!=200:
print('status:{}\nurl:{}\nheaders:{}\nparams:{}'.format(
res.status_code, res.url, headers, params))
return None
df = DataFrame(res.json()['candles'])
df = df.set_index(to_dt(df)).drop('time', axis=1)
df = df.loc[:, ['Ask' not in i for i in df.columns]]
df.columns = df.columns.map(lambda x: x.replace('Bid', '').capitalize())
df.index.name = 'Date'
return df[['Open', 'High', 'Low', 'Close', 'Volume', 'Complete']]
oanda_df = oanda_ohlc('EURUSD', tf='H1', start='20170101', end='20170601')
print(oanda_df.shape)
oanda_df.head(3)
oanda_df['Close'].plot(figsize=(15,3))
とれたヾ(´・ω・`)ノ゙
# 板を取得
asks, bids = (lambda x:(x['asks'],x['bids']))(requests.get('https://api.bitflyer.jp/v1/board').json())
print('len', len(asks), len(bids))
print('asks', asks[:2])
print('bids', bids[:2])
# Seriesに変換
f = lambda x: dict(zip(['index', 'data'], zip(*[[i['price'], i['size']] for i in x])))
ask = Series(**f(asks)).sort_index(ascending=True)
bid = Series(**f(bids)).sort_index(ascending=False)
print('asks\n', ask.head(3))
print('\nbids\n', bid.head(3))
ふむふむ(´・ω・`)
これを
def grouping(book, is_ask=True, gv=100, bins=None, dropna=True):
"""
args: book: pd.Series(data:'size', index:'price')
is_ask: bidの板のときはFalseにする
gv: グルーピングする単位
bins: 少なくすると計算が速い
dropna: 板がない部分を除去するか
"""
idx = book.index.values
max_ = (lambda v: v-v%gv+gv - (gv if is_ask and (v%gv==0) else 0))(idx.max())
min_ = (lambda v: v-v%gv - (gv if is_ask and (v%gv==0) else 0))(idx.min())
bin_ = np.linspace(min_, max_, int((max_-min_)/gv+1))
if bins:
bin_ = bin_[:bins+1] if is_ask else bin_[-(bins+1):]
cut = pd.cut(idx, bin_, right=is_ask)
gb_idx = bin_[1:] if is_ask else bin_[:-1]
gb_book = pd.Series(book.groupby(cut).sum().values, index=gb_idx)
gb_book.sort_index(ascending=is_ask, inplace=True)
if dropna:
gb_book.dropna(inplace=True)
return gb_book
g_ask = grouping(ask, True, 500, 10, True)
g_bid = grouping(bid, False, 500, 10, True)
print('asks\n', g_ask.head(3))
print('\nbids\n', g_bid.head(3))
そして思ったより時間かかる(´・ω・`)
%time g_ask = grouping(ask, True, 500, None, True)
%time g_bid = grouping(bid, False, 500, None, True)
numpyでやってみることにする(´・ω・`)
※これは今日書いた なんか思ったよりてこずった (^ω ^;)
def grouping_np(book, is_ask=True, gv=100, bins=None, dropna=True):
idx = book.index.values
size = book.values
max_ = (lambda v: v-v%gv+gv - (gv if is_ask and (v%gv==0) else 0))(idx.max())
min_ = (lambda v: v-v%gv - (gv if is_ask and (v%gv==0) else 0))(idx.min())
bin_ = np.linspace(min_, max_, int((max_-min_)/gv+1))
if bins:
bin_ = bin_[:bins+1] if is_ask else bin_[-(bins+1):]
mask = (idx>=bin_.min()) & (idx<=bin_.max())
idx = idx[mask]
size = size[mask]
bin_indice = np.digitize(idx, bin_, right=is_ask)
gb_idx = bin_[1:] if is_ask else bin_[:-1]
gb_book = Series(np.bincount(bin_indice-1, weights=size, minlength=len(gb_idx)), index=gb_idx)
gb_book.sort_index(ascending=is_ask, inplace=True)
if dropna:
gb_book = gb_book.loc[gb_book.values>0]
else:
gb_book[gb_book.values==0] = np.nan # 一応さっきのと同じになるようにnanをいれとく
return gb_book
%time g_ask_np = grouping_np(ask, True, 500, None, True)
%time g_bid_np = grouping_np(bid, False, 500, None, True)
わーい!はやくなった!ヾ(´・ω・`)ノ゙
板ぽくしてみます
df = DataFrame({'asks': g_ask_np.iloc[:5], 'bids':g_bid_np.iloc[:5]})
df.index.name = 'price'
df = df.reset_index()[['asks', 'price', 'bids']].sort_values('price', ascending=False)
df['cum_asks'] = df['asks'][::-1].cumsum()
df['cum_bids'] = df['bids'].cumsum()
df = df['cum_asks asks price bids cum_bids'.split()]
df[df.isnull()] = ''
df