Welcome 

Point🛎️

Point Memo


JSON File

銘柄:Sector、Brand
wikipediaで東京証券取引所プライム市場上場企業一覧を取得。
別サイトで33業種区分(Sector)の英訳も取得。
Excelを利用して取得した表からSectorのJSONファイルを作成。
VSCodeで読み込むと容易に整形できる。

[
  {
    "ctgid": "1",
    "name": "ガラス・土石製品",
    "english": "Glass and Ceramics Products"
  },
  {
    "ctgid": "2",
    "name": "ゴム製品",
    "english": "Rubber Products"
  },

    …

  {
    "ctgid": "33",
    "name": "陸運業",
    "english": "Land Transportation"
  }
]

同様に、銘柄(Brand)のJSONファイルを作成。(正規化はしない)

[
  {
    "id": "1301",
    "company": "極洋",
    "category": "水産・農林業",
    "ctgid": "21"
  },
  {
    "id": "1332",
    "company": "ニッスイ",
    "category": "水産・農林業",
    "ctgid": "21"
  },
  {
    "id": "1333",
    "company": "Umios",
    "category": "水産・農林業",
    "ctgid": "21"
  },

    …

  {
    "id": "9997",
    "company": "ベルーナ",
    "category": "小売業",
    "ctgid": "17"
  }
]

農作物獣害
農林水産省の農作物被害状況のデータをJSONファイルに加工。

[
  {
    "animal": "スズメ",
    "damage": [
      {
        "name": " イ ネ",
        "value": 10116
      },
      {
        "name": "ムギ類",
        "value": 220
      },
      {
        "name": "マメ類",
        "value": 25
      },
      {
        "name": "雑 穀",
        "value": 157
      },
      {
        "name": "果 樹",
        "value": 4892
      },
      {
        "name": "飼料作物",
        "value": 6
      },
      {
        "name": "野 菜",
        "value": 695
      },
      {
        "name": "いも類",
        "value": 1
      },
      {
        "name": "工芸作物",
        "value": 28
      },
      {
        "name": "その他",
        "value": 16
      }
    ]
  },
  {
    "animal": "カラス",
    "damage": [
      {
        "name": " イ ネ",
        "value": 6628
      },

    …

      {
        "name": "工芸作物",
        "value": 4512
      },
      {
        "name": "その他",
        "value": 1925
      }
    ]
  }
]

JSON Read

view
import json でjsonのファイルが扱える。(json.load)

import json
import os
------------------------------------------------------------------------------------------------------------------------
class ChartsCategoryView(View):
    def get(self,request):

        # JSONファイルのパスを指定
        json_path = os.path.join(settings.BASE_DIR, 'json/category.json')

        # 読み込みモード r で開く
        with open(json_path, 'r', encoding='utf-8') as f:
            json_data = json.load(f)

        # Templateに渡す
        context = {
            'data': json_data,
        }
        return render(request, 'charts/category.html', context)

JSON Write

view
チャートを書く前にidを元に対象のデータを辞書のリストで取得。

json_path = os.path.join(settings.BASE_DIR, 'json/company.json')
    # 読み込みモードで開く r
    with open(json_path, 'r', encoding='utf-8') as f:
        json_data = json.load(f)

    # 辞書のidが引数のidと同じものを辞書のList(Company)として取得
    company =  [r for r in json_data  if r['id'] == id]

履歴のJSONファイルを読み込んで追加するが、重複しないように辞書のid部分をKeyとする辞書を作成する。

#companyもLISTなので最初の1件を記録の配列の要素として追加
history_data.append(company[0])

#記録の配列内の辞書のidをKeyとして辞書自体をValueとする辞書を作成(重複が省かれる)
unique_dict = {item["id"]: item for item in history_data}

# 重複を省いた辞書のValueをListにする。(要素は辞書で元の形式)
result = list(unique_dict.values())

作成した辞書のLISTをJSONファイルを書き込みモード w で開いてdump出力する。

# 書き込みモードで開く w
with open(write_path, "w", encoding="utf-8") as f:
    json.dump(result, f, ensure_ascii=False, indent=4)

Line Chart

作成方法は以前Blogにも書いた。今回は通常のLine Chartは作ってないけどメモだけ。
matplotlib をimportして作成するがXServerではindex.cgiを工夫しないとエラーになる。

import os
os.environ['OPENBLAS_NUM_THREADS'] = "1"

項目とデータのListをそれぞれ用意してPlotするだけ。
マルチラインだと、タイトル:t_list, データ1:a_list, データ2:b_listとすると

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
------------------------------------------------------------------------------------------------------------------------
plt.plot(t_list, a_list, marker ='o', color="darkgreen")
plt.plot(t_list, b_list, marker ='x', color="black")

ARIMA

Time Seriesから予測を行うARIMA(SARIMA)を試す。
ticker = 銘柄コード + T でYahooからデータをデータフレームとして取得する。

import yfinance as yf
import datetime
from dateutil.relativedelta import relativedelta
import pandas as pd
------------------------------------------------------------------------------------------------------------------------
# 今日
today = datetime.date.today()

# 開始日
past120 =  today + relativedelta(days=-120)

# 検証開始日
past10=today + relativedelta(days=-10)

# データフレーム取得
df = yf.download(ticker, start=past120, end=today)

ARIMAでは p,d,q および P,D,Qのパラメータを決める必要がある。
d,Dを1固定とし、p,q,P,Qを0~2で変動して最小のBICの組み合わせを採用する。

import statsmodels.api as sm
from statsmodels.tsa.statespace.sarimax import SARIMAX
import matplotlib_fontja
import numpy as np
------------------------------------------------------------------------------------------------------------------------
best_params_ab = selectparameter(df['Close'], 5)
------------------------------------------------------------------------------------------------------------------------
def selectparameter(DATA, s):
    dfparm = DATA.reset_index(drop=True)
    p = d = q = range(0, 2)
    pdq = list(itertools.product(p, d, q))
    seasonal_pdq = [(x[0], x[1], x[2], s) for x in list(itertools.product(p, d, q))]
    parameters = []
    parametersaic = []
    BICs = np.array([])
    AICs = np.array([])
    for param in pdq:
        if(param[1] == 1):
            for param_seasonal in seasonal_pdq:
                if(param_seasonal[1] == 1):
                    try:
                        mod = sm.tsa.statespace.SARIMAX(dfparm,
                                                        order=param,
                                                        seasonal_order=param_seasonal)
                        results = mod.fit(maxiter=200)

                        parameters.append([param, param_seasonal, results.bic])
                        BICs = np.append(BICs, results.bic)

                        parametersaic.append([param, param_seasonal, results.aic])
                        AICs = np.append(AICs, results.aic)
                    except:
                        print("error")
                        continue
    return {'BIC':parameters[np.argmin(BICs)],'AIC':parametersaic[np.argmin(AICs)]}

AICも取得してみたが、採用したのはBICの最小の組み合わせ。

best_params = best_params_ab['BIC']
bp=best_params[0][0]
bd=best_params[0][1]
bq=best_params[0][2]
bsp=best_params[1][0]
bsd=best_params[1][1]
bsq=best_params[1][2]
#
p, d, q = bp, bd, bq
P, D, Q, s = bsp, bsd, bsq, 5 
------------------------------------------------------------------------------------------------------------------------
real_price = df['Close']
------------------------------------------------------------------------------------------------------------------------
real_price = real_price.reset_index(drop=True)
model = SARIMAX(real_price, order=(p, d, q), seasonal_order=(P, D, Q, s))
result = model.fit()
------------------------------------------------------------------------------------------------------------------------
# 3. 将来の予測
        forecast_steps = 10
        prediction = result.get_forecast(steps=forecast_steps)
        predicted_mean = prediction.predicted_mean
------------------------------------------------------------------------------------------------------------------------
# 4. 結果のプロット
plt.figure(figsize=(20,9))
plt.plot(realidx, real_price, color='blue',label='Actual Price')
newindex=pd.date_range(start=endday, periods=forecast_steps + 1)[1:]
plt.plot(pd.date_range(start=endday, periods=forecast_steps + 1)[1:], predicted_mean, color='red', label='Forecast')

Bar Chart

積み上げ棒グラフを作成する。
要素の数だけPLOT(plt.bar)を繰り返せばよい。
ただし、2回目以降はそれまでの高さをbottomに指定して上に乗せる感じで描く。
データのListをListにしてチャート描画に引数として渡す。

xmlist=[]
ymlist=[]
is_first = True 

# 動物別Loop
for j in json_data:
    tmplist=[]

    # 穀物別Loop
    for m in j['damage']:

        # 動物の穀物別被害のList
        tmplist.append(m['value'])

        # X軸
        if is_first:
            ymlist.append(m['name'])

    # DataはListのList
    xmlist.append(tmplist)
    is_first = False
create_bar(xmlist, ymlist)

描画する関数では、データのListを展開して都度Plotする。
bottomを求めるのにnp.arrayでそれまでの要素の値を蓄積する。

def create_bar(x_list,r_list):
    plt.cla()
    cnt=0

    # DataのLoop
    for l in x_list:
        # 初回はbottom指定ない
        if cnt == 0:
            plt.bar(r_list,l)
        else:
            # bottom初期化
            bottom_for_next = 0
            # cnt内(描画済みのData)Loopしてnp.arrayで配列を蓄積
            for i in range(cnt):
                bottom_for_next=bottom_for_next + np.array(x_list[i])

            # bottomを指定してPlot
            plt.bar(r_list,l, bottom = bottom_for_next)
        cnt +=1
        
        …


今回はX軸の表示に問題ないがスペースが狭いときには縦書も考慮する。

tmpname = ""
for char in p['name']:
    tmpname=tmpname + char+"\n"

一文字ずつ改行を入れるが、Pythonでは文字列もLoopできる。