investpyを用いたスクリーニング(2)〜テクニカル指標から日経225の買いシグナル、売りシグナル銘柄を抽出

# はじめに

投資情報のポータルサイトである[invest.com](https://www.investing.com/)からAPIライクに情報取得できる[investpy](https://investpy.readthedocs.io/)を使う第二回目。

investing.comが提供しているテクニカル情報は移動平均線、ピボット、そして各種テクニカル指標となる。
前回の記事「[investpyを用いたスクリーニング(1)〜移動平均線からパーフェクトオーダー銘柄を抽出](./86fa8a40572ac2642bb1)」では移動平均線からパーフェクトオーダー銘柄を取得した。
今回は各種テクニカル指標を使ってみる。

# 実装

## 最初の一歩

investing.comは日本株データも取り扱っているので今回は日経225銘柄(参考「[日経平均、ダウなどの構成銘柄一覧を取得する](./58a912a9b75313cffa46)」)を対象にしスクリーニングしてみる。
もちろん、東証上場銘柄すべてを対象(参考「[再編成した東証市場のプライム等区分別銘柄一覧の取得](./0ec7e243c79c0b5488bb)」)にしてもよいが、相当負荷がかかるので試してみる場合は自己責任でお願いしたい。

まずは必要ライブラルのインポート(必要に応じてpipインスール、termcolorは好みで)

```python
import investpy
import pandas as pd
from termcolor import colored as cl
```

次に日経225の銘柄リストをDataFrame化

```python
# Nikkei 225
url = 'https://site1.sbisec.co.jp/ETGate/?OutSide=on&_ControlID=WPLETmgR001Control&_PageID=WPLETmgR001Mdtl20&_DataStoreID=DSWPLETmgR001Control&_ActionID=DefaultAID&getFlg=on&burl=search_market&cat1=market&cat2=none&dir=info&file=market_meigara_225.html'
table_list = pd.read_html(url)
df_nk225_sbi = table_list[1]
df_nk225_sbi = df_nk225_sbi.iloc[:, [0, 1]]
df_nk225_sbi.columns = ['symbol', 'name']
df_index = df_nk225_sbi.set_index('symbol')
```


## investing.comで得られるテクニカル指標

実際に銘柄リストのスクリーニングを行う前に、まずどのようなテクニカル指標が取得できるかトヨタ自動車(7203)で確認する(2022/7/22終値)


`interval`は取り敢えず日足の`daily`で実施

```python
country = 'Japan'
product_type = 'stock'
interval = 'daily' # '1min', '5mins', '30mins', '1hour', '5hour', 'daily', 'weekly', 'monthly'
symbol = '7203'
```

取得

```python
df = investpy.technical_indicators(name=symbol, product_type=product_type,
                                   country=country, interval=interval)

print(cl(f'Technical Indicator for {symbol} in {interval}', attrs=['bold']))
print(df)
```

結果

```
Technical Indicator for 7203 in daily
    technical_indicator     value           signal
0               RSI(14)   55.1120              buy
1            STOCH(9,6)   63.1600              buy
2          STOCHRSI(14)   62.9550              buy
3           MACD(12,26)   65.4000              buy
4               ADX(14)   28.7390             sell
5           Williams %R  -33.2250              buy
6               CCI(14)   95.2873              buy
7               ATR(14)  152.1429  high_volatility
8        Highs/Lows(14)  168.4643              buy
9   Ultimate Oscillator   55.0290              buy
10                  ROC    3.0110              buy
11  Bull/Bear Power(13)  293.9340              buy
```

`technical_indicator`カラムの`RSI(14)`などが指標を表しその横に値`value`とシグナル`signal`が表示されている。
`buy`が買いシグナルで`sell`が売りシグナルであるのでどう取り扱うかだが、素直にシグナルの数に従うことにする。
つまり`buy`や`sell`の合計数が多いものを抽出するようにする。


## シグナルの合計数による抽出

`ATR(14)`を除いた11項目のシグナルが`buy`や`sell`を表示するので今回は合算値10以上のものを対象とする。

```python
criteria = 10
technical_indicators_list = []

print(cl(f'Signal\tPoint\tSymbol\tName', attrs=['bold']))
for symbol in df_index.index.values:
    try:
        name = df_index.loc[symbol, 'name']
        df = investpy.technical_indicators(name=str(symbol), product_type=product_type,
                                           country=country, interval='daily')
        technical_indicators_list.append({'symbol': symbol, 'name': name, 'df': df})
    except Exception as e:
        print(e)
        continue

    buy_count = (df['signal'] == 'buy').sum()
    sell_count = (df['signal'] == 'sell').sum()
    point = buy_count - sell_count
    if point > 0:
        signal = 'buy'
    elif point < 0:
        signal = 'sell'
    else:
        signal = ''
    if abs(point) >= criteria:
        print(f'{signal}\t{point}\t{symbol}\t{name}')
```

結果(2022/7/22終値)

```shell
Signal	Point	Symbol	Name
buy	10	1801	大成建設
buy	10	2002	日清製粉グループ本社
buy	11	4061	デンカ
buy	10	4502	武田薬品工業
buy	11	4689	Zホールディングス
buy	11	4901	富士フイルムホールディングス
sell	-10	5020	ENEOSホールディングス
buy	10	5108	ブリヂストン
buy	10	6479	ミネベアミツミ
buy	11	6753	シャープ
buy	10	7205	日野自動車
buy	11	7733	オリンパス
buy	11	7951	ヤマハ
buy	10	8001	伊藤忠商事
buy	10	8309	三井住友トラスト・ホールディングス
buy	10	8697	日本取引所グループ
sell	-11	8750	第一生命ホールディングス
buy	10	9984	ソフトバンクグループ
```

ENEOSホールディングスと第一生命ホールディングスは売りシグナル。そして残りが買いシグナル。
しかし前回の記事にも書いたがどういう基準(順張り、逆張り)でシグナルを判定しているかはわからないがRSIのデータを見ると順張りのように思える。
トレード期間は`interval`の設定した値に依存するのだろう。なので今回はスイングトレードを想定。

## 独自の条件設定

次はシグナルに頼らず指標の値から独自に抽出条件を設定してみる。
MACDやストキャスティクスは単一情報だけでは判断できないので買われすぎ売られすぎを表すRSIとトレンドを表すADXを使うことにした。

まずADXは20または25以上がトレンド発生中と判断されることが多いので今回は多めの35以上とした。
次にRSIは70や80は買われすぎなので今回50以上60以下というまだ上昇余地のある幅を選んだ。
(数値比較の部分、Pandasのqueryで処理したかったがやり方がよくわからなかった)

```python
result = []
for x in technical_indicators_list:
    symbol = x['symbol']
    name = x['name']
    df = x['df']

    rsi = df.loc[0].value # RSI(14)
    adx = df.loc[4].value # ADX(14)

    if rsi >= 50 and rsi <=60 and adx >= 35:
        result.append((adx, rsi, symbol, name))

for i, x in enumerate(sorted(result, reverse=True)):
    if i == 0:
        print(cl(f'ADX\tRSI\tSymbol\tName', attrs=['bold']))
    adx, rsi, symbol, name = x
    print(f'{adx:.1f}\t{rsi:.1f}\t{symbol}\t{name:<16}')
```

結果(2022/7/22終値)

```shell
ADX	RSI	Symbol	Name
50.8	58.1	4523	エーザイ            
41.6	51.2	9503	関西電力            
41.4	54.8	4568	第一三共            
38.5	54.6	5201	AGC             
37.2	58.0	4631	DIC      
```

エーザイのADXが高く、かつRSIもまだ余裕があるためイケイケなんだろうと思ってチャートみたら本当にそうだった(なお本日7/25瀑下げ中)。

## しかし

エーザイの`ADX(14)`の値が50オーバとかなかなか見ない値だなと思ってYahoo Financeで表示してみると36くらいだった。
`RSI(14)`はだいたい同じくらいでMACDなどもそうだった。
なのでこのADXの算出方法がよくわからないので鵜呑みにするのではなく参考程度に留めるべきだと感じた。

# 最後に

手軽にテクニカル指標が得られる点ではinvestpyならびにinvesting.comは重宝できる。
反面、どういった計算、判断しているかがわからないため参考指標であることを念頭に入れておきたい。

全ソースはこちら
(Google Colabを使う場合は日経225だとデータ量が多くConnection Errorを引き起こすためダウを使用)

[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/higebobo/my-colab/blob/main/investpy_02.ipynb)

https://github.com/higebobo/my-colab/blob/main/investpy_02.ipynb