SageMakerエンドポイントを利用してモデル管理を調べた話

AWSを使用してAIモデルを複数管理する方法 AWSを使用してAIのモデルを複数管理したいという話がありました。 学習済みのモデルなので本番では推論しか使われませんが、モデルのバージョン管理を行いたいということだったので調査をしました。 S3にモデルを置くだけでもある程度管理はできますが、SageMakerのエンドポイントを使うかもしれないということでSageMakerでの管理を調べることになりました。 基本的な書き方はサンプルの書き方に沿ってます。こちらです。 モデルのS3へのアップロード まずはモデルをS3にアップロードするところからです。 # tensorflowを使うのでmodel.tar.gzにモデルを固める TAR_DIR = './tmp' # 一時的なモデルディレクトリ CODE_DIR = './code' # infarence.py等のディレクトリ MODEL_DIR = './model' # モデルディレクトリ TAR_NAME = os.path.join(TAR_DIR , 'model.tar.gz') with tarfile.open(TAR_NAME, mode='w:gz') as tar tar.add(MODEL_DIR) tar.add(CODE_DIR) # モデルをS3にアップロード(複数モデルをアップロードする想定) s3_uri1 = sagemaker.session.Session(default_bucket='development').upload_data( path = TAR_NAME key_prefix = 'image_recognition/test/model1' ) s3_uri2 = sagemaker.session.Session(default_bucket='development').upload_data( path = TAR_NAME key_prefix = 'image_recognition/test/model2' ) イメージの作成 モデルをアップロードしたら次はイメージの作成をします。イメージに関しては1イメージで複数モデル格納できますが、未調査のため一旦複数イメージを作成します。 image_uri1 = sagemaker.image_uris.retrieve( framework='tensorflow', region=sagemaker.session.Session().boto_region_name, version='2.12', instance_type='ml.m5.xlarge', image_scope=inference' ) image_uri2 = sagemaker.image_uris.retrieve( framework='tensorflow', region=sagemaker.session.Session().boto_region_name, version='2.12', instance_type='ml.m5.xlarge', image_scope=inference' ) モデルパッケージグループの作成 モデルパッケージグループの作成をします。この中にモデルを複数入れることでバージョン管理を行っていきます。 ...

2024年8月3日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part9

前回のあらすじ 確率的勾配降下法を使って予測をしてみました。 うまくいかなかったので、別の方法を試すことにしました。 LSTM 時系列分析の代表モデルと言えばLSTMだと思います。 というわけで前回とはプログラムを分けて実装しました。 import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, LSTM, Input import matplotlib.pyplot as plt import glob dm_fol = './datamart/' stock_list = glob.glob(dm_fol + "*.parquet") # データの読み込みと前処理 def preprocess_data(df, time_step=60): df['Close'] = df['Close'].astype(float) data = df[['Close']].values # データのスケーリング scaler = MinMaxScaler(feature_range=(0, 1)) scaled_data = scaler.fit_transform(data) # LSTM用のデータセット作成 X, Y = [], [] for i in range(time_step, len(scaled_data)): X.append(scaled_data[i-time_step:i, 0]) Y.append(scaled_data[i, 0]) X, Y = np.array(X), np.array(Y) X = X.reshape(X.shape[0], X.shape[1], 1) return X, Y, scaler # LSTMモデルの構築 def create_lstm_model(input_shape): model = Sequential() model.add(Input(shape=input_shape)) # Inputオブジェクトを使用して入力形状を指定 model.add(LSTM(50, return_sequences=True)) # model.add(LSTM(50, return_sequences=True, input_shape=input_shape)) model.add(LSTM(50, return_sequences=False)) model.add(Dense(25)) model.add(Dense(1)) model.compile(optimizer='adam', loss='mean_squared_error') return model # モデルの評価とプロット def evaluate_model(df, model, scaler, X_train, y_train, X_test, y_test, time_step, sticker_name): y_train_pred = model.predict(X_train) y_test_pred = model.predict(X_test) y_train_pred = scaler.inverse_transform(y_train_pred) y_test_pred = scaler.inverse_transform(y_test_pred) y_train = scaler.inverse_transform([y_train]) y_test = scaler.inverse_transform([y_test]) train_mse = np.mean((y_train_pred - y_train[0]) ** 2) test_mse = np.mean((y_test_pred - y_test[0]) ** 2) print(f"Train Mean Squared Error: {train_mse}") print(f"Test Mean Squared Error: {test_mse}") # プロット df.set_index('Date', inplace=True) train_dates = df.iloc[time_step:len(y_train[0])+time_step].index test_dates = df.iloc[len(y_train[0])+time_step-1:-1].index plt.figure(figsize=(14, 7)) # plt.plot(train_dates, y_train[0], label='Train Actual', color='black') plt.plot(test_dates, y_test[0], label='Test Actual', color='red') plt.plot(test_dates, y_test_pred, label='Test Predicted', color='blue') plt.title(sticker_name+': Actual vs Predicted Stock Prices') plt.xlabel('Date') plt.ylabel('Close') plt.legend() plt.show() # 次の日の予測 def predict_next_day(model, scaler, df, time_step=60): data = df[['Close']].values last_data = data[-time_step:] last_data_scaled = scaler.transform(last_data) X_input = last_data_scaled.reshape(1, time_step, 1) next_day_prediction = model.predict(X_input) next_day_prediction = scaler.inverse_transform(next_day_prediction) print(f"Next Day Prediction: {next_day_prediction[0][0]}") # データの読み込み for count, stock_data in enumerate(stock_list): df = pd.read_parquet(stock_data) sticker_name = stock_data.split('\\')[1].replace('.parquet', '') # データの前処理 time_step = 60 X, Y, scaler = preprocess_data(df, time_step) # データの分割 train_size = int(len(X) * 0.8) X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = Y[:train_size], Y[train_size:] # モデルの構築と訓練 model = create_lstm_model((X_train.shape[1], 1)) model.fit(X_train, y_train, batch_size=1, epochs=1) # モデルの評価 evaluate_model(df, model, scaler, X_train, y_train, X_test, y_test, time_step, sticker_name) # 次の日の予測 predict_next_day(model, scaler, df, time_step) コード確認 # LSTM用のデータセット作成 X, Y = [], [] for i in range(time_step, len(scaled_data)): X.append(scaled_data[i-time_step:i, 0]) Y.append(scaled_data[i, 0]) X, Y = np.array(X), np.array(Y) X = X.reshape(X.shape[0], X.shape[1], 1) LSTM用のデータセットは60日分のデータを学習として使い、次の日を出力として使用するという特徴があります。 ...

2024年7月24日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part8

前回のあらすじ 株価予測を行うコードをいったん書いてみました。 課題はまだ残ったままですが、今回はそこを解決しつつモデルを追加で学習するというやり方を試してみました。 確率的勾配降下法 def predict_next_day(model, scaler, df): last_row = df.drop(columns=['Close']).iloc[-1].values.reshape(1, -1) # last_row = df.iloc[-1, :-1].values.reshape(1, -1) df.drop(columns=['Close']).iloc[-1].to_csv("test.csv") last_row_scaled = scaler.transform(last_row) next_day_prediction = model.predict(last_row_scaled) print(f"Previous Day Prediction: {df.iloc[-1]['Close']}") print(f"Next Day Prediction: {next_day_prediction[0]}") 前回の予測部分ですが予測するカラムが異なっていたので変な値が出ていました。 修正したことによってだいぶまともな値に修正ができました。 ただ、うまくいくときはきれいな形になっていますがそうでないことも多いです。 波があるところはうまくできている方ですが、直線気味だとうまくいかないですね。 毎回初期化しているのですが、ダメですね。使ってるモデルが確率的勾配降下法も要因としてあるかもしれないです。 というわけで追加学習する形に変更しようと試してみました。 def update_model(model, scaler, new_df): target = new_df['Close'].shift(-1).dropna() features = new_df.drop(columns=['Close']) features = features[:-1] # データのスケーリング X = scaler.transform(features.values) y = target.values model.partial_fit(X, y) # 新しいデータに対する予測と評価 # X_new = scaler.transform(new_df.drop(columns=['Close']).values) X_new = scaler.transform(new_df.drop(columns=['Close']).iloc[:-1].values) y_new = new_df['Close'].shift(-1).dropna().values y_new_pred = model.predict(X_new) mse_new = mean_squared_error(y_new, y_new_pred) print(f"New Data MSE: {mse_new}") for count, stock_data in enumerate(stock_list): ・ ・ ・ if count == 0: model, scaler, X_train, X_test, y_train, y_test = train_model(df) # モデルの評価 y_pred = evaluate_model(model, X_test, y_test) else: update_model(model, scaler, df) ...

2024年7月15日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part7

前回のあらすじ オシレーター系指標の説明変数を追加するコードを書きました。 株価予測_コード 今回やることは株価の予測になります。 今回は1ファイルずつ読み込んで実行しています。ティッカーリストがあればティッカーごとにダウンロードしてきて加工する方法もあったのでいずれやります。 import pandas as pd import numpy as np import yfinance as yf from sklearn.linear_model import SGDRegressor from sklearn.metrics import mean_squared_error from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split import matplotlib.pyplot as plt dm_fol = './datamart/' import glob stock_list = glob.glob(dm_fol + "*.parquet") def preprocess_data(df): df.sort_values('Date', inplace=True) # 日付を特徴量に変換 df['Year'] = df['Date'].dt.year df['Month'] = df['Date'].dt.month df['Day'] = df['Date'].dt.day df['Weekday'] = df['Date'].dt.weekday df['Quarter'] = df['Date'].dt.quarter # 周期成分のエンコーディング df['Month_sin'] = np.sin(2 * np.pi * df['Month'] / 12) df['Month_cos'] = np.cos(2 * np.pi * df['Month'] / 12) df['Day_sin'] = np.sin(2 * np.pi * df['Day'] / 31) df['Day_cos'] = np.cos(2 * np.pi * df['Day'] / 31) df['Weekday_sin'] = np.sin(2 * np.pi * df['Weekday'] / 7) df['Weekday_cos'] = np.cos(2 * np.pi * df['Weekday'] / 7) # 日付を削除 df.drop(columns=['symbol','Date'], inplace=True) # "symbol"以外のobject型カラムをワンホットエンコーディング df = pd.get_dummies(df, columns=[col for col in df.select_dtypes(include=['object']).columns]) # 全ての値が欠損している列を削除 df.dropna(axis=1, how='all', inplace=True) # 値が欠損している行を削除 df.dropna(axis=0, how='any', inplace=True) return df def train_model(df): target = df['Close'].shift(-1).dropna() features = df.drop(columns=['Close']) features = features[:-1] # データのスケーリング scaler = StandardScaler() X = scaler.fit_transform(features.values) y = target.values # データを7:3に分割 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, shuffle=False) model = SGDRegressor(max_iter=1000, tol=1e-3) model.fit(X_train, y_train) return model, scaler, X_test, y_test def evaluate_model(model, scaler, X_test, y_test): y_pred = model.predict(X_test) mse = mean_squared_error(y_test, y_pred) print(f"Mean Squared Error: {mse}") plt.figure(figsize=(14, 7)) plt.plot(y_test, label='Actual', color='black') plt.plot(y_pred, label='Predicted', color='blue') plt.title('Actual vs Predicted Stock Prices') plt.xlabel('Sample') plt.ylabel('Price') plt.legend() plt.show() def predict_next_day(model, scaler, df): last_row = df.iloc[-1, :-1].values.reshape(1, -1) df.iloc[-1, :-1].to_csv("test.csv") last_row_scaled = scaler.transform(last_row) next_day_prediction = model.predict(last_row_scaled) print(f"Next Day Prediction: {next_day_prediction[0]}") # 初回データロードとモデル学習 # start_date = '1990-04-01' # end_date = '2024-07-03' # symbols = ['AAPL', 'MSFT', 'GOOGL'] for stock_data in stock_list: df = pd.read_parquet(stock_data) df = preprocess_data(df) model, scaler, X_test, y_test = train_model(df) # モデルの評価 evaluate_model(model, scaler, X_test, y_test) # 次の日の予測 predict_next_day(model, scaler, df) コードの内容 やったこととしては日付を特徴量に変換しました。 ...

2024年7月6日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part6

前回のあらすじ トレンド系指標の説明変数を追加したところで終わりました。 オシレーター系指標 今回作成したのは RSI RCI 移動平均線乖離率 スローストキャスティクス モメンタムとROC MFI CCI ギャップ ヒストリカル・ボラティリティ def rsi(df): # RSIの計算 window = 14 # 終値の変化 df['Change'] = df['Adj Close'].diff() # 上昇幅と下落幅の計算 df['Gain'] = np.where(df['Change'] > 0, df['Change'], 0) df['Loss'] = np.where(df['Change'] < 0, -df['Change'], 0) # 平均上昇幅と平均下落幅の計算 df['Avg_Gain'] = df['Gain'].rolling(window=window).mean() df['Avg_Loss'] = df['Loss'].rolling(window=window).mean() # 相対力(RS)の計算 df['RS'] = df['Avg_Gain'] / df['Avg_Loss'] # RSIの計算 df['RSI'] = 100 - (100 / (1 + df['RS'])) # シグナルの判定 df['rsi_Signal'] = np.where(df['RSI'] > 70, 'Sell', np.where(df['RSI'] < 30, 'Buy', np.nan)) def calculate_rci(series): n = len(series) date_rank = np.arange(1, n + 1) price_rank = series.rank().values ssd = np.sum((date_rank - price_rank) ** 2) rci = 1 - (6 * ssd) / (n * (n ** 2 - 1)) return rci def rci(df): # RCIの計算 window = 14 df['RCI'] = df['Adj Close'].rolling(window=window).apply(calculate_rci, raw=False) # シグナルの判定(RSIと同様に70以上で売りシグナル、30以下で買いシグナル) df['rci_Signal'] = np.where(df['RCI'] > 70, 'Sell', np.where(df['RCI'] < 30, 'Buy', np.nan)) def madp(df): # 乖離率の計算 df['madp'] = (df['Adj Close'] - df['SMA']) / df['SMA'] * 100 # シグナルの判定 df['madp_Signal'] = np.nan threshold = 5 # 閾値の設定 for i in range(1, len(df)): if df['madp'].iloc[i-1] < -threshold and df['madp'].iloc[i] > df['madp'].iloc[i-1]: df.at[df.index[i], 'madp_Signal'] = 'Buy' elif df['madp'].iloc[i-1] > threshold and df['madp'].iloc[i] < df['madp'].iloc[i-1]: df.at[df.index[i], 'madp_Signal'] = 'Sell' def stochastic(df): # %Kの計算 window = 14 df['14-High'] = df['High'].rolling(window=window).max() df['14-Low'] = df['Low'].rolling(window=window).min() df['%K'] = (df['Adj Close'] - df['14-Low']) / (df['14-High'] - df['14-Low']) * 100 # スロー%Dの計算 df['slow%D'] = df['%K'].rolling(window=3).mean() # シグナルの判定 df['sto_Signal'] = np.nan for i in range(1, len(df)): if df['slow%D'].iloc[i-1] < 20 and df['slow%D'].iloc[i] > df['slow%D'].iloc[i-1]: df.at[df.index[i], 'sto_Signal'] = 'Buy' elif df['slow%D'].iloc[i-1] > 80 and df['slow%D'].iloc[i] < df['slow%D'].iloc[i-1]: df.at[df.index[i], 'sto_Signal'] = 'Sell' def momentum_roc(df): # モメンタムとROCの計算 window = 14 df['Momentum'] = df['Adj Close'] - df['Adj Close'].shift(window) df['ROC'] = ((df['Adj Close'] - df['Adj Close'].shift(window)) / df['Adj Close'].shift(window)) * 100 # トレンドの判定 df['Momentum_Trend'] = np.where(df['Momentum'] > 0, 'Uptrend', np.where(df['Momentum'] < 0, 'Downtrend', 'Neutral')) df['ROC_Trend'] = np.where(df['ROC'] > 0, 'Uptrend', np.where(df['ROC'] < 0, 'Downtrend', 'Neutral')) def mfi(df): # 典型価格(TP)の計算 df['TP'] = (df['High'] + df['Low'] + df['Adj Close']) / 3 # マネーフロー(Raw Money Flow)の計算 df['Raw Money Flow'] = df['TP'] * df['Volume'] # ポジティブマネーフローとネガティブマネーフローの計算 df['Positive Money Flow'] = np.where(df['TP'] > df['TP'].shift(1), df['Raw Money Flow'], 0) df['Negative Money Flow'] = np.where(df['TP'] < df['TP'].shift(1), df['Raw Money Flow'], 0) # 14期間の合計 window = 14 df['Positive Money Flow Sum'] = df['Positive Money Flow'].rolling(window=window).sum() df['Negative Money Flow Sum'] = df['Negative Money Flow'].rolling(window=window).sum() # MFIの計算 df['Money Flow Ratio'] = df['Positive Money Flow Sum'] / df['Negative Money Flow Sum'] df['MFI'] = 100 - (100 / (1 + df['Money Flow Ratio'])) # シグナルの判定 df['mfi_Signal'] = np.nan for i in range(1, len(df)): if df['MFI'].iloc[i-1] < 20 and df['MFI'].iloc[i] > df['MFI'].iloc[i-1]: df.at[df.index[i], 'mfi_Signal'] = 'Buy' elif df['MFI'].iloc[i-1] > 80 and df['MFI'].iloc[i] < df['MFI'].iloc[i-1]: df.at[df.index[i], 'mfi_Signal'] = 'Sell' def cci(df): # 典型価格(TP)の計算 df['TP'] = (df['High'] + df['Low'] + df['Adj Close']) / 3 # 単純移動平均(SMA)の計算 window = 20 df['cci_SMA'] = df['TP'].rolling(window=window).mean() # 偏差(Mean Deviation)の計算 df['Mean Deviation'] = df['TP'].rolling(window=window).apply(lambda x: np.mean(np.abs(x - x.mean())), raw=True) # CCIの計算 df['CCI'] = (df['TP'] - df['cci_SMA']) / (0.015 * df['Mean Deviation']) # シグナルの判定 df['cci_Signal'] = np.nan for i in range(1, len(df)): if df['CCI'].iloc[i-1] < -100 and df['CCI'].iloc[i] > df['CCI'].iloc[i-1]: df.at[df.index[i], 'cci_Signal'] = 'Buy' elif df['CCI'].iloc[i-1] > 100 and df['CCI'].iloc[i] < df['CCI'].iloc[i-1]: df.at[df.index[i], 'cci_Signal'] = 'Sell' def gap(df): # ギャップアップとギャップダウンの計算 df['Previous Close'] = df['Adj Close'].shift(1) df['Gap'] = df['Open'] - df['Previous Close'] df['Gap Type'] = np.where(df['Gap'] > 0, 'Gap Up', np.where(df['Gap'] < 0, 'Gap Down', 'No Gap')) def hv(df): # ヒストリカル・ボラティリティの計算 window = 20 # リターンの計算 df['Return'] = np.log(df['Adj Close'] / df['Adj Close'].shift(1)) # 標準偏差の計算 df['HV'] = df['Return'].rolling(window=window).std() * np.sqrt(252) # df['RCI'] = df['Adj Close'].rolling(window=window).apply(calculate_rci, raw=False) # シグナルの判定 df['hv_Signal'] = np.nan for i in range(1, len(df)): if df['RCI'].iloc[i-1] < -80 and df['RCI'].iloc[i] > df['RCI'].iloc[i-1]: df.at[df.index[i], 'hv_Signal'] = 'Buy' elif df['RCI'].iloc[i-1] > 80 and df['RCI'].iloc[i] < df['RCI'].iloc[i-1]: df.at[df.index[i], 'hv_Signal'] = 'Sell' 次回は予測をしていこうと思います。 ...

2024年7月2日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part5

前回のあらすじ オシレータ系指標とその他の指標について確認しました。 今回は実際にコードに落とし込んで、グラフで見てみようと思います。 作成したコード 今回はとりあえずトレンド系指標の説明変数を見てみたいと思います。クラスかはまだやってないので、いずれやっておきます。 import pandas as pd import numpy as np import matplotlib.pyplot as plt import os out_fol = "./stock_data/" import glob stock_list = glob.glob(out_fol + "*.csv") def moveing_average(df): # 単純移動平均線(SMA)の計算 df['SMA'] = df['Adj Close'].rolling(window=20).mean() # 指数平滑移動平均線(EMA)の計算 df['EMA'] = df['Adj Close'].ewm(span=20, adjust=False).mean() # グラフのプロット plt.figure(figsize=(14, 7)) plt.plot(df['Adj Close'], label='Close Price', color='black') plt.plot(df['SMA'], label='20-Day SMA', color='blue') plt.plot(df['EMA'], label='20-Day EMA', color='red') plt.title('Stock Price with 20-Day SMA and 20-Day EMA') plt.xlabel('Date') plt.ylabel('Price') plt.legend() plt.grid(True) plt.show() def macd(df): # 短期EMA(12日)の計算 short_ema = df['Adj Close'].ewm(span=12, adjust=False).mean() # 長期EMA(26日)の計算 long_ema = df['Adj Close'].ewm(span=26, adjust=False).mean() # MACDラインの計算 df['MACD'] = short_ema - long_ema # シグナルラインの計算(9日間のMACDのEMA) df['Signal_Line'] = df['MACD'].ewm(span=9, adjust=False).mean() # MACDヒストグラムの計算 df['MACD_Histogram'] = df['MACD'] - df['Signal_Line'] # グラフのプロット plt.figure(figsize=(14, 7)) # 終値のプロット plt.subplot(2, 1, 1) plt.plot(df['Close'], label='Close Price', color='black') plt.title('Stock Price and MACD') plt.xlabel('Date') plt.ylabel('Price') plt.legend() # MACDとシグナルラインのプロット plt.subplot(2, 1, 2) plt.plot(df['MACD'], label='MACD', color='blue') plt.plot(df['Signal_Line'], label='Signal Line', color='red') plt.bar(df.index, df['MACD_Histogram'], label='MACD Histogram', color='gray') plt.xlabel('Date') plt.ylabel('Value') plt.legend() plt.tight_layout() plt.show() def bollinger_bands(df): # 中央バンド(20日間の単純移動平均線)の計算 df['Middle_Band'] = df['Adj Close'].rolling(window=20).mean() # 標準偏差の計算 df['STD'] = df['Adj Close'].rolling(window=20).std() # 上部バンドの計算 df['Upper_Band'] = df['Middle_Band'] + (2 * df['STD']) # 下部バンドの計算 df['Lower_Band'] = df['Middle_Band'] - (2 * df['STD']) # 過熱感の判断 df['bands_buy_flg'] = df['Adj Close'] > df['Lower_Band'] df['bands_sell_flg'] = df['Adj Close'] < df['Upper_Band'] # グラフのプロット plt.figure(figsize=(14, 7)) plt.plot(df['Adj Close'], label='Close Price', color='black') plt.plot(df['Middle_Band'], label='Middle Band (SMA 20)', color='blue') plt.plot(df['Upper_Band'], label='Upper Band (Middle + 2*STD)', color='red') plt.plot(df['Lower_Band'], label='Lower Band (Middle - 2*STD)', color='green') plt.fill_between(df.index, df['Upper_Band'], df['Lower_Band'], color='grey', alpha=0.1) plt.scatter(df.index[df['bands_buy_flg']], df['Adj Close'][df['bands_buy_flg']], label='bands_buy_flg', color='red', marker='o') plt.scatter(df.index[df['bands_sell_flg']], df['Adj Close'][df['bands_sell_flg']], label='bands_sell_flg', color='green', marker='o') plt.title('Bollinger Bands with bands_buy_flg and bands_sell_flg Signals') plt.xlabel('Date') plt.ylabel('Price') plt.legend() plt.grid(True) plt.show() def ichimoku_kinko_hyo(df): # 転換線(過去9日間の最高値と最安値の平均値) df['Tenkan_sen'] = (df['High'].rolling(window=9).max() + df['Low'].rolling(window=9).min()) / 2 # 基準線(過去26日間の最高値と最安値の平均値) df['Kijun_sen'] = (df['High'].rolling(window=26).max() + df['Low'].rolling(window=26).min()) / 2 # 先行スパン1(転換線と基準線の平均値を26日先にプロット) df['Senkou_Span_A'] = ((df['Tenkan_sen'] + df['Kijun_sen']) / 2).shift(26) # 先行スパン2(過去52日間の最高値と最安値の平均値を26日先にプロット) df['Senkou_Span_B'] = ((df['High'].rolling(window=52).max() + df['Low'].rolling(window=52).min()) / 2).shift(26) # 遅行スパン(現在の終値を26日遅らせてプロット) df['Chikou_Span'] = df['Adj Close'].shift(-26) # 雲の上・下の判定とシグナル df['Signal'] = np.where(df['Tenkan_sen'] > df['Kijun_sen'], 'Buy', 'Sell') df['Trend'] = np.where(df['Adj Close'] > df[['Senkou_Span_A', 'Senkou_Span_B']].max(axis=1), 'Uptrend', np.where(df['Adj Close'] < df[['Senkou_Span_A', 'Senkou_Span_B']].min(axis=1), 'Downtrend', 'Neutral')) # グラフのプロット plt.figure(figsize=(14, 7)) plt.plot(df['Adj Close'], label='Close Price', color='black') plt.plot(df['Tenkan_sen'], label='Tenkan-sen (Conversion Line)', color='blue') plt.plot(df['Kijun_sen'], label='Kijun-sen (Base Line)', color='red') plt.plot(df['Senkou_Span_A'], label='Senkou Span A (Leading Span 1)', color='green') plt.plot(df['Senkou_Span_B'], label='Senkou Span B (Leading Span 2)', color='orange') plt.plot(df['Chikou_Span'], label='Chikou Span (Lagging Span)', color='purple') # 先行スパンの領域を塗りつぶす plt.fill_between(df.index, df['Senkou_Span_A'], df['Senkou_Span_B'], where=df['Senkou_Span_A'] >= df['Senkou_Span_B'], color='lightgreen', alpha=0.5) plt.fill_between(df.index, df['Senkou_Span_A'], df['Senkou_Span_B'], where=df['Senkou_Span_A'] < df['Senkou_Span_B'], color='lightcoral', alpha=0.5) plt.title('Ichimoku Kinko Hyo (Ichimoku Cloud)') plt.xlabel('Date') plt.ylabel('Price') plt.legend() plt.grid(True) plt.show() # シグナルとトレンドの表示 print(df[['Adj Close', 'Tenkan_sen', 'Kijun_sen', 'Signal', 'Trend']].tail(30)) def directional_movement_index(df): # True Range(TR)の計算 df['TR'] = df[['High', 'Low', 'Adj Close']].apply(lambda x: max(x['High'] - x['Low'], abs(x['High'] - x['Adj Close']), abs(x['Low'] - x['Adj Close'])), axis=1) # +DMと-DMの計算 df['+DM'] = df['High'].diff().apply(lambda x: x if x > 0 else 0) df['-DM'] = df['Low'].diff().apply(lambda x: -x if x < 0 else 0) # 14期間のTR、+DM、-DMの合計 df['TR14'] = df['TR'].rolling(window=14).sum() df['+DM14'] = df['+DM'].rolling(window=14).sum() df['-DM14'] = df['-DM'].rolling(window=14).sum() # +DIと-DIの計算 df['+DI14'] = 100 * (df['+DM14'] / df['TR14']) df['-DI14'] = 100 * (df['-DM14'] / df['TR14']) # DXの計算 df['DX'] = 100 * (abs(df['+DI14'] - df['-DI14']) / (df['+DI14'] + df['-DI14'])) # ADXの計算 df['ADX'] = df['DX'].rolling(window=14).mean() # シグナルとトレンド強度の判定 df['Signal'] = np.where(df['+DI14'] > df['-DI14'], 'Buy', 'Sell') df['Trend_Strength'] = np.where(df['ADX'] >= 25, 'Strong', 'Weak') # ADXのトレンド(前日と比べて上昇または下降を判定) df['ADX_Trend'] = df['ADX'].diff().apply(lambda x: 'Uptrend' if x > 0 else 'Downtrend' if x < 0 else 'No Change') # グラフのプロット plt.figure(figsize=(14, 7)) plt.plot(df['+DI14'], label='+DI (Positive Directional Indicator)', color='green') plt.plot(df['-DI14'], label='-DI (Negative Directional Indicator)', color='red') plt.plot(df['ADX'], label='ADX (Average Directional Index)', color='blue') plt.title('DMI (Directional Movement Index)') plt.xlabel('Date') plt.ylabel('Value') plt.legend() plt.grid(True) plt.show() # 結果の表示 print(df[['+DI14', '-DI14', 'ADX', 'Signal', 'Trend_Strength']].tail(30)) def parabolic(df): # パラボリックSARの計算 df['SAR'] = np.nan df['EP'] = np.nan df['AF'] = np.nan # 初期値設定 initial_trend = 'up' if df['Adj Close'].iloc[1] > df['Adj Close'].iloc[0] else 'down' initial_AF = 0.02 max_AF = 0.2 # 初期SAR、EP、AFの設定 df.at[df.index[1], 'SAR'] = df['Low'].iloc[0] if initial_trend == 'up' else df['High'].iloc[0] df.at[df.index[1], 'EP'] = df['High'].iloc[1] if initial_trend == 'up' else df['Low'].iloc[1] df.at[df.index[1], 'AF'] = initial_AF # パラボリックSARの計算ループ for i in range(2, len(df)): prev_SAR = df['SAR'].iloc[i-1] prev_AF = df['AF'].iloc[i-1] prev_EP = df['EP'].iloc[i-1] trend = 'up' if df['Adj Close'].iloc[i-1] > prev_SAR else 'down' if trend == 'up': SAR = prev_SAR + prev_AF * (prev_EP - prev_SAR) EP = max(prev_EP, df['High'].iloc[i]) AF = min(prev_AF + 0.02, max_AF) if df['High'].iloc[i] > prev_EP else prev_AF else: SAR = prev_SAR - prev_AF * (prev_SAR - prev_EP) EP = min(prev_EP, df['Low'].iloc[i]) AF = min(prev_AF + 0.02, max_AF) if df['Low'].iloc[i] < prev_EP else prev_AF # トレンドの反転 if trend == 'up' and df['Low'].iloc[i] < SAR: SAR = prev_EP EP = df['Low'].iloc[i] AF = initial_AF trend = 'down' elif trend == 'down' and df['High'].iloc[i] > SAR: SAR = prev_EP EP = df['High'].iloc[i] AF = initial_AF trend = 'up' df.at[df.index[i], 'SAR'] = SAR df.at[df.index[i], 'EP'] = EP df.at[df.index[i], 'AF'] = AF # シグナルの判定 df['Signal'] = np.where((df['Adj Close'].shift(1) < df['SAR'].shift(1)) & (df['Adj Close'] > df['SAR']), 'Sell', np.where((df['Adj Close'].shift(1) > df['SAR'].shift(1)) & (df['Adj Close'] < df['SAR']), 'Buy', np.nan)) # グラフのプロット plt.figure(figsize=(14, 7)) plt.plot(df['Adj Close'], label='Close Price', color='black') plt.plot(df['SAR'], label='Parabolic SAR', linestyle='dashed', color='blue') plt.scatter(df[df['Signal'] == 'Buy'].index, df[df['Signal'] == 'Buy']['Adj Close'], marker='^', color='green', label='Buy Signal', s=100) plt.scatter(df[df['Signal'] == 'Sell'].index, df[df['Signal'] == 'Sell']['Adj Close'], marker='v', color='red', label='Sell Signal', s=100) plt.title('Parabolic SAR with Buy and Sell Signals') plt.xlabel('Date') plt.ylabel('Price') plt.legend() plt.grid(True) plt.show() # 結果の表示 print(df[['Adj Close', 'SAR', 'EP', 'AF', 'Signal']].tail(30)) def Envelope(df): # エンベロープの計算 percentage = 0.02 # 2% のエンベロープ df['Upper Envelope'] = df['SMA'] * (1 + percentage) df['Lower Envelope'] = df['SMA'] * (1 - percentage) # シグナルの判定 df['Signal'] = np.where(df['Adj Close'] > df['Upper Envelope'], 'Sell', np.where(df['Adj Close'] < df['Lower Envelope'], 'Buy', np.nan)) # グラフのプロット plt.figure(figsize=(14, 7)) plt.plot(df['Adj Close'], label='Close Price', color='black') plt.plot(df['SMA'], label='20-Day SMA', color='blue') plt.plot(df['Upper Envelope'], label='Upper Envelope (SMA + 2%)', color='green') plt.plot(df['Lower Envelope'], label='Lower Envelope (SMA - 2%)', color='red') plt.scatter(df[df['Signal'] == 'Buy'].index, df[df['Signal'] == 'Buy']['Adj Close'], marker='^', color='green', label='Buy Signal', s=100) plt.scatter(df[df['Signal'] == 'Sell'].index, df[df['Signal'] == 'Sell']['Adj Close'], marker='v', color='red', label='Sell Signal', s=100) plt.title('Envelopes with Buy and Sell Signals') plt.xlabel('Date') plt.ylabel('Price') plt.legend() plt.grid(True) plt.show() # 結果の表示 print(df[['Adj Close', 'SMA', 'Upper Envelope', 'Lower Envelope', 'Signal']].tail(30)) for stock_data in stock_list: # データフレームの作成 df = pd.read_csv(stock_data) df['Date'] = pd.to_datetime(df['Date']) df.set_index('Date', inplace=True) moveing_average(df) macd(df) bollinger_bands(df) ichimoku_kinko_hyo(df) directional_movement_index(df) parabolic(df) Envelope(df) os.system("pause") 実行結果の確認 コードの作成が完了したので実行してグラフを見てみます。実行したデータはAppleの20年分とMcDonald’sの1年分になります。比較してみてみようと思います。 ...

2024年6月25日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part4

前回までのあらすじ 株価の基本情報とトレント系指標について見てみました。 今回はオシレーター系指標とその他について見ていこうと思います。 技術分析データ オシレーター系指標 RSI(相対力指数): 株価の過熱感を示す指標。 サイコロジカルライン:一定期間の中で株価が上昇した日数の割合を示す。市場の投資家心理を測る指標。 RCI:日付の順位と価格の順位の相関関係を示し、トレンドの強さを判断する指標。 移動平均線乖離率:現在の株価と移動平均線との乖離を示しす。価格が移動平均線からどれだけ離れているかを判断する指標。 スローストキャスティクス:ストキャスティクスの変動を滑らかにする。買われ過ぎや売られ過ぎの状態をより安定して示す指標。 モメンタムとROC:モメンタムは価格の変化のスピードを示す。ROCは一定期間の価格変動率を示す指標。 MFI:出来高を加味したRSIに似た指標。買われ過ぎや売られ過ぎを判断するための指標。 CCI:価格と移動平均線の乖離を基に、トレンドの強さと異常値を判断する指標。 その他 ヒストリカル・ボラティリティ:過去の一定期間の価格変動の大きさを測定した指標。 ギャップ(ギャップアップ、ギャップダウン):前日の終値と当日の始値の差で市場の初期のトレンド。 レジスタンスライン:株価が上昇する際に止まりやすい価格帯のこと。 サポートライン:株価が下落する際に止まりやすい価格帯のこと。 軽く調べただけでこれくらいあるんですね。ローソク足を使ったりチャートの動きを使う指標もありましたが、今回は割愛します。他にも使いたいデータはありますので。 技術分析データ_補足説明 RSI (Relative Strength Index, 相対力指数) 株価の過熱感を示すオシレータータイプの指標で0~100の範囲で表す。14日間のデータを使用するのが一般的。 70以上: 買われ過ぎ(Overbought)を示し、価格の反転を予想。 30以下: 売られ過ぎ(Oversold)を示し、価格の上昇を予想 RCI(Rank Correlation Index) 株価の日付順位と価格順位の相関を示す指標。トレンドの強さと方向を判断するために使用される。 各日付に順位を付ける(最新の日を1位とする)。各価格にも順位を付ける(高い価格を1位とする)。日付順位と価格順位の差を二乗して合計。RCIを計算。 RCI=1 − 6∑(日付順位−価格順位)^2 / n(n^2−1) 移動平均線乖離率(Moving Average Convergence Divergence, MACD) 現在の株価と移動平均線との乖離を示す。価格が移動平均線からどれだけ離れているかを判断する指標。 移動平均線(通常は25日移動平均線)を計算。現在の株価と移動平均線の差を求める。その差を移動平均線で割り、百分率で表示する。 乖離率=(現在の株価 − 移動平均線) / 移動平均線 ×100 乖離率が大きくマイナスに乖離した後に反転したら買いシグナル。乖離率が大きくプラスに乖離した後に反転したら売りシグナル スローストキャスティクス(Slow Stochastic Oscillator) ストキャスティクスの変動を滑らかにする。買われ過ぎや売られ過ぎの状態をより安定して示す指標 ストキャスティクスとは価格が特定の期間内でどれだけ高値と安値の間にあるかを示す指標。スロー以外にもファストがあるがここでは割愛。 過去N日間(通常は14日間)の最高値と最安値を求める。現在の終値から最安値を引き、最高値と最安値の差で割る。この値に100を掛ける。%Kの値が出る。過去3日間の%Kラインの平均を求める。%Dの値が出る。%Dの単純移動平均を求める。Slow%Dの値が出る。 スロー%Dが20以下から上昇し始めたら買いシグナル、スロー%Dが80以上から下落し始めたら売りシグナル。 モメンタム(Momentum) 一定期間内の価格変動の速度や勢いを示す指標。トレンドの強さや反転の可能性を判断する。プラスの値は上昇トレンドを、マイナスの値は下降トレンドを示す。 momentum = 現在の株価 - N期間前の株価 ROC(Rate of Change) モメンタムを百分率で表したもので、トレンドの強さを評価する。プラスの値は上昇トレンドを、マイナスの値は下降トレンドを示す.。 ROC = ((現在の株価 - N期間前の株価) / N期間前の株価) * 100 MFI(Money Flow Index) 出来高を加味したRSIに似た指標で、市場の過熱感を判断するために使用される。MFIが80以上で下落し始めたら売りシグナル、20以下で上昇し始めたら買いシグナル。 TP = H + L + C / 3 (TP: その日の取引価格の中央値、H: 最高値、L: 最安値、C: 終値) ...

2024年6月22日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part3

株価予測_前回のおさらい 前回はティッカー一覧を取得できたので、株価を取得する方法を書きました。株価取得のコードはpart1とそこまで大きな差はないですが… 株価予測_今回やること 今回は予測の前に使用する変数について記載していきます。 株価で取得した値は6つになります。 ただし、トレーダーの一部の人は組み合わせて説明変数を作って使っていると思います。 なのでChat-GPTに質問を投げた後、説明変数を見ていこうと思います。 株価とは 特定の時間における株式の市場価格を示します。この値は技術分析で使用される「移動平均線、RSI、MACD」などで使用されます。株価の情報は以下のデータが存在します。 変数名 説明 Open(始値) 引日の最初の取引価格。ギャップを分析できる。 High(高値) 取引日の中で最も高い取引価格。レジスタンラインの形成にも使用する。 Low(安値) 取引日の中で最も低い取引価格。サポート来の形成にも使用する。 Close(終値) 取引日の最後の取引価格。 Adj Close(調整後終値) 分割や配当を調整した後の終値。 Volume(出来高) 取引日の中で売買された株式の総数。 出来高についての補足 特定の期間に取引された株式の数量を示します。出来高の増減は市場の関心度やトレンドの強さを示します。また、高い出来高を伴う価格変動は信頼性が高く、トレンドが続く可能性がある。 技術分析データについて 株価からわかる基本的な情報はこれで以上になります。この情報を組み合わせて変数を作り、そのデータを株価予測に使用していきます。次は技術分析についてです。 技術分析はザックリ分けると以下の2タイプに分かれます。 トレンド系指標(順張り系指標) オシレーター系指標(逆張り系指標) この2つを組み合わせることでだましに合わず有効活用できると言われています。※だまし(理論通りの動きとならず反対の動きをすること) まずはトレンド系指標から見ていこうと思います。他にも指標はありますが文量が多くなるので次回に回します。 トレンド系指標 移動平均線: 一定期間の平均株価。 MACD(移動平均収束拡散法): 短期と長期の移動平均線の差。 ボリンジャーバンド: 株価の変動範囲を示す指標。 一目均衡表:市場のトレンド、サポート・レジスタンス、買い・売りのシグナルを同時に把握できる総合的なテクニカル指標。 DMI:上昇トレンドと下降トレンドの強さを示し、相場の方向性を判断するための指標。 パラボリック:トレンドの転換点を示し、上昇トレンドでは株価の下、下降トレンドでは株価の上に点を描く指標。 エンベロープ:一定期間の移動平均線に対して上下に一定割合だけ離れたバンドを描き、過熱感を判断する指標。 技術分析データ_補足説明 移動平均線 (Moving Average, MA) 一定期間の平均株価を計算し、その期間が過ぎると新しいデータで更新される指標。 単純移動平均線 (Simple Moving Average, SMA):指定された期間の株価の平均値を計算。例:5日移動平均線、25日移動平均線、75日移動平均線 指数平滑移動平均線 (Exponential Moving Average, EMA):最近のデータに重みを置いて計算する移動平均線。 MACD (Moving Average Convergence Divergence, 移動平均収束拡散法) 短期のEMAと長期のEMAの差を基にした指標。3つの要素で構成され、MACDラインがシグナルラインを上抜けると買いシグナル、下抜けると売りシグナルとされる。 MACDライン: 12日EMAと26日EMAの差 シグナルライン: 9日EMA(MACDラインのEMA) ...

2024年6月19日

WordPressにパスキーを導入してセキュリティ意識を高めよう!

はじめに ここ最近セキュリティに関するニュースが後を絶たないですね…。例えば 岡山の病院で患者情報流出 ニコニコ動画サイバー攻撃 積水ハウス個人情報流出 流出や攻撃だけでも頻繁に起きますし、脆弱性の発見も日々起こっています。こちらのサイトなどで見ることができます。 そこで自身もセキュリティ意識を高めるため、パスワードではなくパスキーを使ったWordPressのログインを試みようという話になります。 設定手順 まずはWordPressにログインして「OwnID Passwordless Login」をインストールします。その後設定画面に移動すると以下の画像画面に行くので、「OwnID Console.」をクリックします。 OwnID Console画面に入ったらアカウントを作ってログインしましょう!Githubがあればそちらでも大丈夫です。 ログインができたら「Create Application」でアプリの作成を行います。 まずはアプリ名を決めましょう。適当で大丈夫です。 アプリ名を決めたら使用するシステムを選択しましょう!今回の場合はWordPressになります。 もし開発に使用する場合は以下から選択することになると思います。いつか開発で使ってみたいですね。 WordPressの場合は自身のURLサイトを設定しましょう。 設定が完了したら準備完了です! 複数サイト設定 ここから先は複数作る場合になります。カスタムドメインで作ると複数パターン設定できます。 カスタムドメインをまずは作ります。基本は「passwordless.あなたのドメイン」で設定します。 カスタムドメインの設定が完了したらDNSにStep1とStep2の値を設定します。 設定が完了してチェックが通れば「Verified」になります。 設定が完了したら「App ID」と「Shared Secret」の画面を出したまま、WordPressの画面に戻ります。 OwnIDの設定画面で先ほどのApp IDとShared secretを入力して完了です。 ...

2024年6月16日

短期売買と分析力が向上しそうな株価予測をだらだらとやる part2

前回までの話 前回ティッカーが取れないという話をしたがあれは嘘だ。 pyppeteerを使うといったがあれも嘘だ。 ティッカー取得時の注意点 前回作成したものからほとんど変えることなくSBIに記載されている全てのティッカーを取得することができました。 ただ、注意点があります。 アメリカ以外の国ではティッカーの後に特定の文字列をつける必要がある。 ベトナムの「DCL」であれば後ろに「.VN」をつけて「DCL.VN」にする必要がある。 中国(香港)の「000621」であれば後ろに「.HK」をつけて、さらに前の0を削除して「00621.HK」にする必要がある。 シンガポールとマレーシアに関しては扱うティッカーの文字列がそもそも違うので使えない。 日本の場合は東京で扱っているものは後ろに「.T」、札幌であれば「.S」が必要。 前回の修正箇所 日本はまだ取得してないですが上記の点に注意して、コード書いていく必要があります。修正した個所はここ sbi_foreign_stock_list = [ {"america": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_usequity_list.html", "tag": "table", "c_cd":"", "class": "foo_table md-l-table-01 md-l-utl-mt10"}}, {"china": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_hk_list.html", "tag": "div", "c_cd":".HK", "class": "accTbl01"}}, {"korea": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_kr_list.html", "tag": "div", "c_cd":".KS", "class": "accTbl01"}}, {"russia": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_ru_list.html", "tag": "div", "c_cd":".ME", "class": "accTbl01"}}, {"vietnam": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_vn_list.html", "tag": "div", "c_cd":".VN", "class": "accTbl01"}}, {"Indonesia": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_id_list.html", "tag": "div", "c_cd":".JK", "class": "accTbl01"}}, # {"Singapore": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_sg_list.html", "tag": "div", "c_cd":".SI", "class": "accTbl01"}}, # SBIとyahooのティカーが一致しない件 {"thailand": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_th_list.html", "tag": "div", "c_cd":".BK", "class": "accTbl01"}}, # {"malaysia": {"url": "https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_my_list.html", "tag": "div", "c_cd":".KL", "class": "accTbl01"}}, # SBIとyahooのティカーが一致しない件(SBIは英略、yahooは数値) ] 株価取得コード 修正するとティッカーリストが作られるので、取得したティッカーリストをもとに株価を取得すると以下のようなコードになります。 ...

2024年6月13日