pythonでローソク足(candle chart)の描画

# matplotlib.financeでローソク足

## データの作成
ランダムウォークで架空の為替チャートを作成します。

```python
import numpy as np
import pandas as pd


def randomwalk(periods=None, start=None, end=None, freq='B', tz=None,
               normalize=False, name=None, closed=None, tick=1, **kwargs):
    """Returns random up/down pandas Series.

    Usage:
        ```
        import datetime
        randomwalk(100)  # Returns +-1up/down 100days from now.
        randomwalk(100, freq='H')  # Returns +-1up/down 100hours from now.
        randomwalk(100, ,tick=0.1 freq='S')  # Returns +-0.1up/down 100seconds from now.
        randomwalk(100, start=datetime.datetime.today())  # Returns +-1up/down 100days from now.
        randomwalk(100, end=datetime.datetime.today())
            # Returns +-1up/down back to 100 days from now.
        randomwalk(start=datetime.datetime(2000,1,1), end=datetime.datetime.today())
            # Returns +-1up/down from 2000-1-1 to now.
        randomwalk(100, freq='H').resample('D').ohlc()  # random OHLC data
        ```

    Args:
        periods: int
        start: start time (default datetime.now())
        end: end time
        freq: ('M','W','D','B','H','T','S') (default 'B')
        tz: time zone
        tick: up/down unit size (default 1)

    Returns:
        pandas Series with datetime index
    """
    if not start and not end:
        start = pd.datetime.today().date()  # default arg of `start`
    index = pd.DatetimeIndex(start=start, end=end, periods=periods, freq=freq, tz=tz,
                             normalize=normalize, name=name, closed=closed, **kwargs)
    bullbear = pd.Series(tick * np.random.randint(-1, 2, len(index)),
                         index=index, name=name, **kwargs)  # tick * (-1,0,1のどれか)
    price = bullbear.cumsum()  # 累積和
    return price
```


```python
np.random.seed(1)  # ランダムステートのリセット。常に同じランダムウォークが出来上がる
rw = randomwalk(60*24*90, freq='T', tick=0.01)
rw.head(5)
```




    2017-03-19 00:00:00    0.00
    2017-03-19 00:01:00   -0.01
    2017-03-19 00:02:00   -0.02
    2017-03-19 00:03:00   -0.02
    2017-03-19 00:04:00   -0.02
    Freq: T, dtype: float64




```python
rw.plot()
```

![README_4_1.png](https://qiita-image-store.s3.amazonaws.com/0/113494/78e5aac0-886f-7336-8b95-e7f9f53ab1af.png)





最小tick0.01円の1分足を30日分生成


```python
df = rw.resample('B').ohlc() + 115  # 初期値は115円
df.head()
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>open</th>
      <th>high</th>
      <th>low</th>
      <th>close</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>2017-03-17</th>
      <td>115.00</td>
      <td>115.38</td>
      <td>114.76</td>
      <td>115.36</td>
    </tr>
    <tr>
      <th>2017-03-20</th>
      <td>115.37</td>
      <td>115.49</td>
      <td>115.03</td>
      <td>115.15</td>
    </tr>
    <tr>
      <th>2017-03-21</th>
      <td>115.14</td>
      <td>115.69</td>
      <td>115.07</td>
      <td>115.65</td>
    </tr>
    <tr>
      <th>2017-03-22</th>
      <td>115.66</td>
      <td>116.22</td>
      <td>115.64</td>
      <td>116.21</td>
    </tr>
    <tr>
      <th>2017-03-23</th>
      <td>116.20</td>
      <td>116.47</td>
      <td>115.93</td>
      <td>116.11</td>
    </tr>
  </tbody>
</table>
</div>


resampleメソッド使って平日のみの日足(オプション how='B')に直し、open, high, low, closeの4本値(ohcl)にまとめました。


```python
df.plot()
```






![README_8_1.png](https://qiita-image-store.s3.amazonaws.com/0/113494/c63d4247-86d9-f0f4-6c5f-8554c0f13833.png)


4本値グラフは上のように見づらいので、ローソク足に直します。



## 参考1
参考: [stack over flow - how to plot ohlc candlestick with datetime in matplotlib?](http://stackoverflow.com/questions/36334665/how-to-plot-ohlc-candlestick-with-datetime-in-matplotlib)


```python
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.finance as mpf
from matplotlib import ticker
import matplotlib.dates as mdates
import pandas as pd

def candlechart(ohlc, width=0.8):
    """入力されたデータフレームに対してローソク足チャートを返す
        引数:
            * ohlc:
                *データフレーム
                * 列名に'open'", 'close', 'low', 'high'を入れること
                * 順不同"
            * widrh: ローソクの線幅
        戻り値: ax: subplot"""
    fig, ax = plt.subplots()
    # ローソク足
    mpf.candlestick2_ohlc(ax, opens=ohlc.open.values, closes=ohlc.close.values,
                          lows=ohlc.low.values, highs=ohlc.high.values,
                          width=width, colorup='r', colordown='b')

    # x軸を時間にする
    xdate = ohlc.index
    ax.xaxis.set_major_locator(ticker.MaxNLocator(6))

    def mydate(x, pos):
        try:
            return xdate[int(x)]
        except IndexError:
            return ''

    ax.xaxis.set_major_formatter(ticker.FuncFormatter(mydate))
    ax.format_xdata = mdates.DateFormatter('%Y-%m-%d')

    fig.autofmt_xdate()
    fig.tight_layout()

    return fig, ax

candlechart(df)
```




    (<matplotlib.figure.Figure at 0x207a86dd080>,
     <matplotlib.axes._subplots.AxesSubplot at 0x207a6a225c0>)


![README_11_1.png](https://qiita-image-store.s3.amazonaws.com/0/113494/68b413aa-0aa3-a086-1ba2-a3a6af004ce2.png)



## 参考2
参考: [Qiita - Pythonでローソク足チャートの表示（matplotlib編）
](http://qiita.com/toyolab/items/1b5d11b5d376bd542022)


```python
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.finance as mpf
from matplotlib import ticker
import matplotlib.dates as mdates
import pandas as pd

fig = plt.figure()
ax = plt.subplot()

ohlc = np.vstack((range(len(df)), df.values.T)).T #x軸データを整数に
mpf.candlestick_ohlc(ax, ohlc, width=0.8, colorup='r', colordown='b')

xtick0 = (5-df.index[0].weekday())%5 #最初の月曜日のインデックス

plt.xticks(range(xtick0,len(df),5), [x.strftime('%Y-%m-%d') for x in df.index][xtick0::5])
ax.grid(True) #グリッド表示
ax.set_xlim(-1, len(df)) #x軸の範囲
fig.autofmt_xdate() #x軸のオートフォーマット
```


![README_13_0.png](https://qiita-image-store.s3.amazonaws.com/0/113494/d2ac16c2-98a8-9fd5-3de9-09501eed4c4e.png)


## SMA(Simple Moving Average)の追加


```python
import matplotlib.pyplot as plt
import matplotlib.finance as mpf
from randomwalk import *

fig = plt.figure()
ax = plt.subplot()

# candle
ohlc = np.vstack((range(len(df)), df.values.T)).T  # x軸データを整数に
mpf.candlestick_ohlc(ax, ohlc, width=0.8, colorup='r', colordown='b')

# sma
sma = df.close.rolling(5).mean()
vstack = np.vstack((range(len(sma)), sma.values.T)).T  # x軸データを整数に
ax.plot(vstack[:, 0], vstack[:, 1])

# xticks
xtick0 = (5 - df.index[0].weekday()) % 5  # 最初の月曜日のインデックス
plt.xticks(range(xtick0, len(df), 5), [x.strftime('%Y-%m-%d') for x in df.index][xtick0::5])
ax.grid(True)  # グリッド表示
ax.set_xlim(-1, len(df))  # x軸の範囲
fig.autofmt_xdate()  # x軸のオートフォーマット
plt.show()

```

![README_15_0.png](https://qiita-image-store.s3.amazonaws.com/0/113494/4e5fd874-ebf8-3ca7-920c-088ea4331b8d.png)




```python
import matplotlib.pyplot as plt
import matplotlib.finance as mpf

def sma(ohlc, period):
    sma = ohlc.close.rolling(period).mean()
    vstack = np.vstack((range(len(sma)), sma.values.T)).T  # x軸データを整数に
    return vstack

fig = plt.figure()
ax = plt.subplot()

# candle
ohlc = np.vstack((range(len(df)), df.values.T)).T  # x軸データを整数に
mpf.candlestick_ohlc(ax, ohlc, width=0.8, colorup='r', colordown='b')

# sma
sma5 = sma(df, 5)
sma25 = sma(df, 25)
ax.plot(sma5[:, 0], sma5[:, 1])
ax.plot(sma25[:, 0], sma25[:, 1])


# xticks
xtick0 = (5 - df.index[0].weekday()) % 5  # 最初の月曜日のインデックス
plt.xticks(range(xtick0, len(df), 5), [x.strftime('%Y-%m-%d') for x in df.index][xtick0::5])
ax.grid(True)  # グリッド表示
ax.set_xlim(-1, len(df))  # x軸の範囲
fig.autofmt_xdate()  # x軸のオートフォーマット
plt.show()

```

![README_16_0.png](https://qiita-image-store.s3.amazonaws.com/0/113494/66ea1590-ffec-a74d-f5ee-43671b0b2034.png)



# plotlyでローソク足

## plotlyの練習
参考: [Qiita - [Python] Plotlyでぐりぐり動かせるグラフを作る
](http://qiita.com/inoory/items/12028af62018bf367722)

初めてplotlyを使うので、やりかた

`conda install plotly`

でインストールして以下のようにインポートします。

アカウントを作る必要あるやらないやら情報がいろいろありますが、規制緩和されて、今では無料である程度やりたい放題みたいです。


```python
import plotly as py
py.offline.init_notebook_mode(connected=False) 
```

適当なサンプルデータを作ります。


```python
fo = [[2000,1190547,1.36],
    [2001,1170662,1.33],
    [2002,1153855,1.32],
    [2003,1123610,1.29],
    [2004,1110721,1.29],
    [2005,1062530,1.26],
    [2006,1092674,1.32],
    [2007,1089818,1.34],
    [2008,1091156,1.37],
    [2009,1070035,1.37],
    [2010,1071304,1.39],
    [2011,1050806,1.39],
    [2012,1037101,1.41],
    [2013,1029816,1.43],
    [2014,1003532,1.42],
    [2015,1005656,1.46]]
raw = pd.DataFrame(fo, columns=['year', 'births', 'birth rate'])
raw
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>year</th>
      <th>births</th>
      <th>birth rate</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>2000</td>
      <td>1190547</td>
      <td>1.36</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2001</td>
      <td>1170662</td>
      <td>1.33</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2002</td>
      <td>1153855</td>
      <td>1.32</td>
    </tr>
    <tr>
      <th>3</th>
      <td>2003</td>
      <td>1123610</td>
      <td>1.29</td>
    </tr>
    <tr>
      <th>4</th>
      <td>2004</td>
      <td>1110721</td>
      <td>1.29</td>
    </tr>
    <tr>
      <th>5</th>
      <td>2005</td>
      <td>1062530</td>
      <td>1.26</td>
    </tr>
    <tr>
      <th>6</th>
      <td>2006</td>
      <td>1092674</td>
      <td>1.32</td>
    </tr>
    <tr>
      <th>7</th>
      <td>2007</td>
      <td>1089818</td>
      <td>1.34</td>
    </tr>
    <tr>
      <th>8</th>
      <td>2008</td>
      <td>1091156</td>
      <td>1.37</td>
    </tr>
    <tr>
      <th>9</th>
      <td>2009</td>
      <td>1070035</td>
      <td>1.37</td>
    </tr>
    <tr>
      <th>10</th>
      <td>2010</td>
      <td>1071304</td>
      <td>1.39</td>
    </tr>
    <tr>
      <th>11</th>
      <td>2011</td>
      <td>1050806</td>
      <td>1.39</td>
    </tr>
    <tr>
      <th>12</th>
      <td>2012</td>
      <td>1037101</td>
      <td>1.41</td>
    </tr>
    <tr>
      <th>13</th>
      <td>2013</td>
      <td>1029816</td>
      <td>1.43</td>
    </tr>
    <tr>
      <th>14</th>
      <td>2014</td>
      <td>1003532</td>
      <td>1.42</td>
    </tr>
    <tr>
      <th>15</th>
      <td>2015</td>
      <td>1005656</td>
      <td>1.46</td>
    </tr>
  </tbody>
</table>
</div>




```python
data = [
    py.graph_objs.Scatter(y=raw["births"], name="births"),
]
layout = py.graph_objs.Layout(
    title="title",
    legend={"x":0.8, "y":0.1},
    xaxis={"title":""},
    yaxis={"title":""},
)
fig = py.graph_objs.Figure(data=data, layout=layout)
py.offline.iplot(fig, show_link=False)
```

![newplot1.png](https://qiita-image-store.s3.amazonaws.com/0/113494/f6eb7e21-e3ad-1376-8698-d59d277e6c52.png)



```python
data = [
    py.graph_objs.Bar(x=raw["year"], y=raw["births"], name="Births"),
    py.graph_objs.Scatter(x=raw["year"], y=raw["birth rate"], name="Birth Rate", yaxis="y2")
]
layout = py.graph_objs.Layout(
    title="Births and Birth Rate in Japan",
    legend={"x":0.8, "y":0.1},
    xaxis={"title":"Year"},
    yaxis={"title":"Births"},
    yaxis2={"title":"Birth Rate", "overlaying":"y", "side":"right"},
)
fig = py.graph_objs.Figure(data=data, layout=layout)
py.offline.iplot(fig)
#py.offline.plot(fig)
```


![newplot2.png](https://qiita-image-store.s3.amazonaws.com/0/113494/d00a1ed9-e5d8-24b0-3390-99492974e3ec.png)



操作方法

* マウスオーバーで数値の表示
* ドラッグで拡大
* ダブルクリックで元のビューに戻る

## 為替チャート
参考: [Qiita - Pythonでローソク足チャートの表示（Plotly編）](http://qiita.com/toyolab/items/db8a1e539d4f995079d5)


```python
from plotly.offline import init_notebook_mode, iplot
from plotly.tools import FigureFactory as FF
init_notebook_mode(connected=True) # Jupyter notebook用設定
```



### 通常のプロット
candleチャートの関数が用意されているので、open, high, low, closeのデータが用意できればローソク足のグラフは簡単に作成できます。

ただし、平日のみの表示ができません。土日も表示されます。


```python!
fig = FF.create_candlestick(df.open, df.high, df.low, df.close, dates=df.index)
py.offline.iplot(fig)
```


![newplot3.png](https://qiita-image-store.s3.amazonaws.com/0/113494/38f002d7-7f37-7600-bbbc-b85379fa04bc.png)


### 平日のみのプロット
参考先の方が平日のみのindexに直していました。


```python
fig = FF.create_candlestick(df.open, df.high, df.low, df.close)

xtick0 = (5-df.index[0].weekday())%5 #最初の月曜日のインデックス
fig['layout'].update({
    'xaxis':{
        'showgrid': True,↔
        'ticktext': [x.strftime('%Y-%m-%d') for x in df.index][xtick0::5],
        'tickvals': np.arange(xtick0,len(df),5)
    }
})

py.offline.iplot(fig)
```

![newplot4.png](https://qiita-image-store.s3.amazonaws.com/0/113494/9592cbe2-e512-cd74-b095-20a120fee0e6.png)




## 指標の追加


```python
def sma(data, window, columns='close'):
    return data[columns].rolling(window).mean()

sma5 = sma(df, 5)
```


```python
fig = FF.create_candlestick(df.open, df.high, df.low, df.close, dates=df.index)

add_line = Scatter( x=df.index,  y=df.close,  name= 'close values',
                   line=Line(color='black'))
fig['data'].extend([add_line])
↔
py.offline.iplot(fig, filename='candlestick_and_trace', validate=False)
```

![newplot5.png](https://qiita-image-store.s3.amazonaws.com/0/113494/07bb3e79-253e-c58c-67c6-04527ccaf4bc.png)



```python
from plotly.graph_objs import *
fig = FF.create_candlestick(df.open, df.high, df.low, df.close, dates=df.index)
add_line = [Scatter(x=df.index, y=df.close.rolling(5).mean(), name='SMA5', line=Line(color='r')),
            Scatter(x=df.index, y=df.close.rolling(15).mean(), name='SMA15', line=Line(color='b')),
            Scatter(x=df.index, y=df.close.rolling(25).mean(), name='SMA25', line=Line(color='g'))]
↔
fig['data'].extend(add_line)
fig['layout'].update({'xaxis':{'showgrid': True}})

py.offline.iplot(fig, filename='candlestick_and_trace', validate=False)
```

![newplot6.png](https://qiita-image-store.s3.amazonaws.com/0/113494/784ad3dc-5dbe-c6f0-ecbe-6b721e7d5c2d.png)



## SMA, EMA比較
新たなチャートの作成


```python
np.random.seed(10)
ra = randomwalk(60*24*360, freq='T', tick=0.01) + 115
df1 = ra.resample('B').ohlc()
```


```python
import plotly.graph_objs as go
fig = FF.create_candlestick(df1.open, df1.high, df1.low, df1.close, dates=df1.index)
add_line = [go.Scatter(x=df1.index, y=df1.close.rolling(75).mean(), name='SMA75', line=Line(color='r')),
            go.Scatter(x=df1.index, y=df1.close.ewm(75).mean(), name='EMA75', line=Line(color='b'))]

fig['data'].extend(add_line)
fig['layout'].update({'xaxis':{'showgrid': True}})
    
py.offline.iplot(fig, filename='candlestick_and_trace', validate=False)
```

![newplot7.png](https://qiita-image-store.s3.amazonaws.com/0/113494/c13be963-8b20-c837-acb3-162d20de0914.png)


何故か移動平均がガタガタしているので、拡大してみます。


```python
import plotly.graph_objs as pyg
from datetime import datetime

def to_unix_time(*dt):
    """datetimeをunix秒に変換
    引数: datetimeの入ったリスト
    戻り値: unix秒に直されたリスト"""
    epoch =  datetime.utcfromtimestamp(0)
    ep = [(i - epoch).total_seconds() * 1000 for i in list(*dt)]
    return ep

fig = FF.create_candlestick(df1.open, df1.high, df1.low, df1.close, dates=df1.index)
add_line = [pyg.Scatter(x=df1.index, y=df1.close.rolling(75).mean(), name='SMA75', line=Line(color='r')),
            pyg.Scatter(x=df1.index, y=df1.close.ewm(75).mean(), name='EMA75', line=Line(color='b')),
            pyg.Scatter(x=df1.index, y=df1.close.rolling(75).mean(), name='SMA75', mode='markers'),
            pyg.Scatter(x=df1.index, y=df1.close.ewm(75).mean(), name='EMA75', mode='markers')]

fig['data'].extend(add_line)  # プロットするデータの追加
fig['layout'].update(xaxis = {'showgrid': True,
                               'type': 'date',
                               'range':to_unix_time([datetime(2017,9,1), datetime(2018,1,1)])})  # レイアウトの変更
    
py.offline.iplot(fig, filename='candlestick_and_trace', validate=False)
```


![newplot8.png](https://qiita-image-store.s3.amazonaws.com/0/113494/1b561ec6-22e4-bdf1-ebe4-3e161db0a97b.png)


横軸に休日が描かれていますが、移動平均線データの休日の値はNaNです。
故に、金曜日と月曜日を結ぶ直線ができてしまい、滑らかにスムージングしたはずの線がガタガタに見えます。


ちなみに参考の人がやっていたようにlayoutでxaxisを無理やり平日だけにするとSAM, EMAがプロットされなくなりました。
これは休日をなくすべくxaxisをstringとfloatに無理やり直す処理をしているから、SMAとEMAのindexとあわなくなったためでしょう。
SMA, EMAのindexもstring, float混合のindexにすれば平日のみxaxisにできなくもないでしょうが、今後時間足を任意の長さに変更することを想定していますので、無理にdatetime型を崩したくありません。

そのため休日が入って少し見づらいですが、plotlyのAPIをそのまま受け入れていきます。
平日だけのxaxisにする何かいい方法を知っている方がいたらコメントください。
まだまだplotlyのことよくわかっていないです。


Next
[plotlyでキャンドルチャートプロット](http://qiita.com/u1and0/items/0ebcf097a1d61c636eb9#_reference-c5cef3d11c5b351c26b8)