investpyを用いたスクリーニング(1)〜移動平均線からパーフェクトオーダー銘柄を抽出

# はじめに

[investing.com](https://www.investing.com/)は株価や経済指標など有益な投資情報を提供しているポータルサイトである。
一方Yahoo FinanceのようにAPIによるデータ取得はできない。(参考: [APIは提供されますか。 – Investing\.com サポート](https://www.investing-support.com/hc/ja/articles/115005473825-API%E3%81%AF%E6%8F%90%E4%BE%9B%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%81%8B-))
しかし[investpy](https://investpy.readthedocs.io/)を用いるればPythonで簡単に操作できる。

今回パーフェクトオーダーと呼ばれるチャート分析法を用いて該当銘柄を抽出する。

## パーフェクトオーダーとは

順張り(株価が上昇している時に買う、または下降している時に売る)に用いられる手法の一つで移動平均線が短期、中期、長期の順で並んでいる状態を指し、トレンドが形成されていないか判断するシグナルである。
上昇の場合は短期>中期>長期。下降は長期>中期>短期の順。

短期・中期・長期の組み合わせとしては「5-10-20」が一般的だが「アレンの4-9-18日手法」というのもある。
investing.comで利用できるのは5日,10日,20日,50日,100日,200日の6種類である。

そのためアレンの手法は使えないが「5-10-20-50-100-200」といった6本線まで拡張できる(いわゆるレインボーライン)。
本数が多いほどより限定されたものを抜粋できる。

# 使い方

## 前準備

pipを用いてライブラリのインストール

```shell
pip install investpy
```

上記ライブラリのインポート

```python
import datetime

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

## 対象銘柄の選定

スクリーニング対象の銘柄選定については今回はニューヨーク・ダウの30銘柄とする。
取得方法は以前投稿した記事([日経平均、ダウなどの構成銘柄一覧を取得する](./58a912a9b75313cffa46))を参考していただきたい。

```python
# Dow Jones
url = 'https://en.wikipedia.org/wiki/Dow_Jones_Industrial_Average'
table_list = pd.read_html(url)
dji = table_list[1].iloc[:,[2,0]]
dji.columns = ['symbol', 'name']
df_index = dji.set_index('symbol')
```

## 移動平均値の取得

### パラメータ

まず変数やパラメータを設定する。

```python
signal = {
    'buy': [],
    'sell': []
}

country = 'United States'
product_type = 'stock'
ma_key = 'ema_value' # or sma_value
period_num = 6 # set value from 2 to 5 (5,10,20,50,100,200)
```

* `signal`: スクリーニング結果を格納する変数
* `country`: 対象国。今回はダウなので`United States`(日本株の場合は`Japan`)
* `product_type`: 株価の場合は`stock`
* `ma_key`: 単純移動平均(`sma_value`)と指数平滑移動平均(`ema`)があるので今回は後者の`ema_value`を設定
* `period_num`: 移動平均線を何本使うかの値。3とした場合5-10-20となる。 

### 抽出

```python
for symbol in df_index.index.values:
  name = df_index.loc[symbol, 'name']
  df_ma = investpy.moving_averages(name=symbol, product_type='stock', country=country)
  ma = df_ma[ma_key]
  raw_order = ma[:period_num].to_list()

  if raw_order == sorted(raw_order, reverse=True):
      key = 'buy'
  elif raw_order == sorted(raw_order):
      key = 'sell'
  else:
      key = None

  if key:
      signal[key].append((symbol, name, df_ma[['period', 'sma_value', 'ema_value']]))
```

#### 上記解説

キモとなるのは以下の箇所。
`name`にはティッカーや銘柄コードを入れる。

```python
df_ma = investpy.moving_averages(name=symbol, product_type=product_type, country=country)
```

`df_ma`の出力はこんな感じ。

```
  period  sma_value sma_signal  ema_value ema_signal
0      5     145.48        buy     145.37        buy
1     10     145.03        buy     144.29        buy
2     20     141.40        buy     143.83        buy
3     50     145.94       sell     145.65       sell
4    100     150.55       sell     148.43       sell
5    200     151.24       sell     148.54       sell
```

`buy`や`sell`とかご丁寧に教えていただいているが順張りか逆張りか、スイングトレードかポジショントレードかなどスタイルがわからないので今回はバッサリと数値データ3項目だけを抽出。

```python
df_ma[['period', 'sma_value', 'ema_value']]
```

#### スライス

移動平均線を何本使うかを後方を削るスライス処理しているが、前方部分をスライス(除去)して長期的な視野で見る方法もある。

```python
raw_order = ma[:period_num].to_list()
```

#### パーフェクトオーダー判定ロジック

ロジックというほどのものではないが

```python
if raw_order == sorted(raw_order, reverse=True):
    key = 'buy'
elif raw_order == sorted(raw_order):
    key = 'sell'
else:
    key = None
```

リストの並びの判定をしている。
元データが並び替えデータと一致するかどうかというふうに。

降順の場合

```python
a = [3, 2, 1]
a == sorted(a, reverse=True)
True
a == sorted(a)
False
```

昇順の場合

```python
a = [1, 2, 3]
a == sorted(a, reverse=True)
False
a == sorted(a)
True
```

どちらでも無い場合

```python
a = [3, 1, 2]
a == sorted(a)
False
a == sorted(a, reverse=True)
False
```

もっとスマートな方法があれば教えていただきたい。

### 結果

出力

```python
for key in signal:
    if signal[key]:
        print(cl(f'{key.capitalize()} signal', attrs=['bold', 'blink']))
        print('\n')
        for symbol, name, df in signal[key]:
            print(cl(f'{symbol} - {name}', attrs=['bold']))
            print(df.loc[:period_num-1, ['period', ma_key]])
            print('\n')
        print('\n\n')
```

結果(2022年7月14日実施したものを抜粋)

```
Buy signal

KO - Coca-Cola
  period  ema_value
0      5      62.80
1     10      62.65
2     20      62.62
3     50      62.58
4    100      62.00
5    200      60.37

...

Sel signal

MSFT - Microsoft
  period  ema_value
0      5     258.15
1     10     259.50
2     20     260.26
3     50     265.30
4    100     276.29
5    200     281.17
```

買いシグナルはパフェット銘柄の代名詞コカ・コーラ(KO)など4銘柄。
逆に売りシグナルはマイクロソフト(MSFT)はじめ多数。

> (注記)
> 買いシグナル・売りシグナルという表現はあくまでもパーフェクトオーダーの並びでの判定結果に基づく。
> トレンド判定は後述しているように他の要素と合わせて総合的に判断しなければならない。

# まとめ

investpyを用いて株価のトレンドを判断するためのパーフェクトオーダーを算出する手法を紹介した。
investing.com自体はapiの提供をしておらず、investpyは下記ページのような分析結果をrequestsやlxmlを用いてスクレイピングしているので参考になる。

https://www.investing.com/equities/apple-computer-inc-technical

今年の2月あたりから米国株が弱いので売りシグナル銘柄のほうが多い結果となっている。
また買いシグナルのコカ・コーラも6ヶ月チャートで見ると上昇トレンドなのかよくわからない。

今回の手法ではあくまでも短期・中期・長期の移動平均線の並びだけでパーフェクトオーダー判定している。
しかし銘柄をある程度絞り込むといった用途に関しては十分効果的だと思う。

実際のトレンドはチャートと照らし合わせ、各移動平均線の並びや間隔、角度などを総合的に見ないと判断できない。
また場合によっては他のテクニカル指標も参考にするのがよい。

テクニカル指標に関しては今回取り上げた移動平均を含め本来は自分で算出するべきだと思うし実際はそうしている。
ただし、手軽に利用できる点や自分の算出データとの答え合わせの意味ではこういうパブリックな指標活用も有用だと思う。

全ソースは以下。

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