自分のキャリアをあれこれ考えながら、Pythonで様々なデータを分析していくブログです

【ナップサック問題】単元未満株と楽天銀行の株式配当金受取プログラムでお得な組み合わせは何かシュミレーションしてみる その2

Data Analytics
Data Analytics
本記事の内容を利用する場合は自己責任でお願いいたします。投資を勧めている訳ではありません。

前回、単元未満株と楽天銀行の配当金受取プログラムでお得な組み合わせは何かシュミレーションの方向性を考えました。

【ナップサック問題】単元未満株と楽天銀行の株式配当金受取プログラムでお得な組み合わせは何かシュミレーションしてみる
本記事の内容を利用する場合は自己責任でお願いいたします。投資を勧めている訳ではありません。「単元未満株」と楽天銀行の「株式配当金受取プログラム」を組み合わせたときに一番お得な組み合わせは何かPythonで計算してみようと思います。数年前、単...

今回は実際に2022/11/25の株価情報でシュミレーションしてみました。

結果は、パターン1で「日本郵船」のみを37株購入した場合の18880円のリターンが最高でした。

その他のパターンもまとめると下記になります。

・(パターン2) ランダム1銘柄ずつピックアップし合計11万円分を購入 (100万回試行)
→ 4824円のリターン (54銘柄)

・(パターン3) 利回りが高い順に1銘柄ずつ合計11万円分を購入
→ 8496円のリターン (59銘柄)

・(パターン4) 株価が安い順に1銘柄ずつ合計11万円分を購入
→ 6118円のリターン (454銘柄)

・(パターン5) 配当金が高い順に1銘柄ずつ合計11万円分を購入
→ 3181円のリターン (5銘柄)

スポンサーリンク

データの読み込みと加工

株価データはkabudata-dll.comさんのデータをダウンロードして使用させていただきました。利用される際にはkabudata-dll.comさんのサイトの注意事項をご確認ください。

import pandas as pd
import numpy as np
df = pd.read_csv("/home/studio-lab-user/sagemaker-studiolab-notebooks/20221125.csv", encoding='shift-jis')
df.head(1).transpose()
Out[0]

0
市場 プライム(内国株式)
業種 水産・農林業
銘柄コード 1301
名称 極洋
現在日付 2022/11/25
前日終値 3750.0
始値 3755
高値 3785
安値 3745
終値 3775
出来高 9000.0
逆日歩 0.0
信用売残 1600.0
信用買残 13600.0
配当 90.0
配当落日 2023/3/30
PER 8.25
PBR 0.87
# 空白のみのデータがあるのでNaNに変換
df = df.replace(r'^\s+$', np.nan, regex=True)

# NaNのデータは除去
drop_indexes = df[df.isnull().any(axis=1)].index
df = df.drop(index=drop_indexes)
df.info()
Out[0]
Int64Index: 3756 entries, 0 to 3784
Data columns (total 18 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   市場      3756 non-null   object 
 1   業種      3756 non-null   object 
 2   銘柄コード   3756 non-null   int64  
 3   名称      3756 non-null   object 
 4   現在日付    3756 non-null   object 
 5   前日終値    3756 non-null   float64
 6   始値      3756 non-null   object 
 7   高値      3756 non-null   object 
 8   安値      3756 non-null   object 
 9   終値      3756 non-null   object 
 10  出来高     3756 non-null   float64
 11  逆日歩     3756 non-null   float64
 12  信用売残    3756 non-null   float64
 13  信用買残    3756 non-null   float64
 14  配当      3756 non-null   float64
 15  配当落日    3756 non-null   object 
 16  PER     3756 non-null   float64
 17  PBR     3756 non-null   float64
dtypes: float64(8), int64(1), object(9)
memory usage: 557.5+ KB

終値などのデータ型がObjectになっているのでfloatに変換した方が良さそうです。

# データ型の指定
dict_dtypes={
 '市場': 'object',
 '業種': 'object',
 '銘柄コード': 'int64',
 '名称': 'object',
 '現在日付': 'object',
 '前日終値': 'float64',
 '始値': 'float64',
 '高値': 'float64',
 '安値': 'float64',
 '終値': 'float64',
 '出来高': 'float64',
 '逆日歩': 'float64',
 '信用売残': 'float64',
 '信用買残': 'float64',
 '配当': 'float64',
 '配当落日': 'object',
 'PER': 'float64',
 'PBR': 'float64'
}
# データ型の指定
df = df.astype(dict_dtypes)
BUDGET=110000 # 予算は11万円
RAKUTEN_HAITO_PROGRAM = 10 # 配当金受け取りプログラムの金額
スポンサーリンク

(パターン1) 各銘柄を予算内で買えるだけ買った場合のリターン

# 必要な変数の作成と計算
df2 = df.copy()
df2["shares_to_hold"] = BUDGET // df2["終値"]
df2["return"] = df2["配当"] * df2["shares_to_hold"] + RAKUTEN_HAITO_PROGRAM
df2["利回り"] = df2["配当"] / df2["終値"]
df2["sim利回り"] = df2["return"] / (df2["終値"] * df2["shares_to_hold"])
df2[["業種","名称","終値","配当","PER","PBR","shares_to_hold","return","利回り","sim利回り"]].sort_values(by="return",ascending=False).head(10)
Out[0]

業種 名称 終値 配当 PER PBR shares_to_hold return 利回り sim利回り
3415 海運業 日本郵船 2947.5 510.0 1.45 0.61 37.0 18880.0 0.173028 0.173120
3416 海運業 商船三井 3250.0 550.0 1.48 0.63 33.0 18160.0 0.169231 0.169324
3487 海運業 乾汽船 1841.0 173.0 4.95 1.43 59.0 10217.0 0.093971 0.094063
3418 海運業 NSユナイテッド海運 3745.0 340.0 3.39 0.66 29.0 9870.0 0.090788 0.090880
38 鉱業 三井松島ホールディングス 3055.0 270.0 2.20 0.92 36.0 9730.0 0.088380 0.088471
1724 鉄鋼 日本製鉄 2258.5 180.0 3.10 0.52 48.0 8650.0 0.079699 0.079791
3417 海運業 川崎汽船 2618.0 200.0 0.99 0.48 42.0 8410.0 0.076394 0.076485
40 鉱業 石油資源開発 4195.0 300.0 4.29 0.57 26.0 7810.0 0.071514 0.071605
89 建設業 西松建設 3930.0 285.0 11.49 1.00 27.0 7705.0 0.072519 0.072613
476 食料品 日本食品化工 2572.0 180.0 5.06 0.55 42.0 7570.0 0.069984 0.070077

海運業のリターンが高いようですね。

利回り17%や16%とかになっていますが、日本郵船に関しては企業ページに配当金推移があり、2021年から急に上がったようです。

あとは決算の説明会資料を読んで今後もこのトレンドが続くかどうか検討でしょうか。

ちなみにJPXの資料によると11月のプライム市場の単純平均利回りは2.18%だそうです。

1つの株に集中してしまうのも少し怖い気はします。

スポンサーリンク

(パターン2) ランダムにピックアップした銘柄を1銘柄ずつ合計11万円分購入

ランダムにシャッフルしたデータを使って計算しようと思います。

とりあえず100万回試したうち、一番リターンが大きい組み合わせを採用しました。

次のステップとして、並列処理にして1000万回試すとかやってもいいかも知れません。

# 変数定義
best_sum_dividend = 0
best_sum_purchase_amount = 0
best_stocks_comb = []
from datetime import datetime

# 100万回試行する (並列処理に変更した方がいいかも)
for i in range(1000000):

    BUDGET=110000 # 予算は11万円
    row_list = [] # 加工済みレコード格納用
    sum_purchase_amount = 0 # 購入金額合計
    sum_dividend = 0 # 配当金合計

    # https://stackoverflow.com/questions/29576430/shuffle-dataframe-rows
    for row in df.sample(frac=1).itertuples():

        if (BUDGET - row.終値) > 0:
            BUDGET = BUDGET - row.終値
            #print("BUY",row.名称, "BUDGET remain:",BUDGET)
        else:
            #print("skip:",row.名称)
            continue

        sum_purchase_amount = sum_purchase_amount + row.終値
        sum_dividend = sum_dividend + row.配当 + RAKUTEN_HAITO_PROGRAM

        # listにIndexを格納
        row_list.append(row.Index)

    if sum_dividend > best_sum_dividend:
        best_sum_dividend = sum_dividend
        best_sum_purchase_amount = sum_purchase_amount
        best_stocks_comb = row_list
# 一番リターンが良かった組み合わせの合計配当金額と合計購入金額と利回り
print(best_sum_dividend,best_sum_purchase_amount,best_sum_dividend/best_sum_purchase_amount)
Out[0]
4824.0 109998.0 0.043855342824414986
# 一番リターンが良かった組み合わせ
df[["業種","名称","終値","配当","PER","PBR"]].loc[best_stocks_comb]
Out[0]

業種 名称 終値 配当 PER PBR
2295 電気機器 テックポイント・インク JDR 990.0 0.0 0.00 0.00
818 繊維製品 ホギメディカル 3550.0 70.0 18.72 1.03
2070 機械 帝国電機製作所 2390.0 116.0 12.65 1.39
875 情報・通信業 サイバーリンクス 1146.0 13.0 16.75 2.06
3031 卸売業 丸紅 1582.5 75.0 5.21 0.99
3070 卸売業 佐藤商事 1232.0 63.0 4.56 0.50
3330 不動産業 センチュリー21・ジャパン 1007.0 45.0 16.67 1.67
3390 陸運業 遠州トラック 2651.0 94.0 8.99 1.02
355 食料品 アサヒグループホールディングス 4451.0 111.0 15.39 1.09
2897 その他製品 アミファ 633.0 24.0 20.09 0.82
2186 電気機器 シンフォニアテクノロジー 1502.0 60.0 6.32 0.76
2749 小売業 コジマ 637.0 14.0 8.47 0.79
481 食料品 シノブフーズ 632.0 20.0 6.86 0.53
3593 サービス業 ビジネスコーチ 2162.0 50.0 15.01 4.93
1383 医薬品 栄研化学 1991.0 48.0 12.68 1.51
1390 医薬品 中京医薬品 242.0 5.0 63.68 0.99
3688 サービス業 ナック 941.0 40.0 11.74 0.97
160 建設業 三晃金属工業 3090.0 155.0 5.98 0.55
1349 情報・通信業 ビザスク 1990.0 0.0 0.00 5.52
2569 その他金融業 日本モーゲージサービス 884.0 20.0 11.81 1.82
121 建設業 金下建設 2860.0 50.0 51.34 0.36
3535 情報・通信業 日本通信 235.0 0.0 97.91 39.36
468 食料品 セイヒョー 9370.0 50.0 80.63 3.12
3297 その他金融業 NECキャピタルソリューション 2096.0 74.0 6.94 0.41
1574 化学 ノエビアホールディングス 5870.0 215.0 26.04 3.85
2744 小売業 ハウス オブ ローゼ 1620.0 25.0 84.81 1.44
48 建設業 東急建設 662.0 36.0 17.37 0.74
2217 サービス業 ウェルビー 918.0 0.0 96.63 6.40
3415 海運業 日本郵船 2947.5 510.0 1.45 0.61
2362 電気機器 リオン 2080.0 45.0 14.61 1.00
3539 情報・通信業 KDDI 4106.0 135.0 13.04 1.76
3156 小売業 青山商事 1032.0 21.0 14.29 0.32
1668 ゴム製品 不二ラテックス 1960.0 50.0 7.76 0.74
2428 電気機器 山一電機 1902.0 87.0 6.57 1.09
3504 倉庫・運輸関連業 兵機海運 1894.0 115.0 4.47 0.58
3048 卸売業 中央魚類 2988.0 60.0 12.56 0.50
1759 鉄鋼 日本精線 4465.0 210.0 8.89 0.75
3283 保険業 MS&ADインシュアランスグループホールディングス 4150.0 200.0 15.83 0.78
952 情報・通信業 データ・アプリケーション 1590.0 43.0 16.77 1.22
3665 情報・通信業 アイネス 1469.0 40.0 15.27 0.87
1788 非鉄金属 昭和電線ホールディングス 1747.0 60.0 5.80 0.87
2304 電気機器 ナカヨ 1093.0 40.0 37.43 0.28
1635 建設業 ドラフト 420.0 5.0 7.02 1.47
3286 証券、商品先物取引業 スパークス・グループ 1743.0 60.0 15.50 2.88
3076 卸売業 神鋼商事 4485.0 300.0 4.48 0.56
2641 輸送用機器 松屋アールアンドディ 1215.0 5.0 20.35 1.64
3251 その他金融業 イオンフィナンシャルサービス 1487.0 50.0 11.06 0.73
3631 情報・通信業 DTS 3510.0 120.0 19.01 2.60
2693 卸売業 小野建 1466.0 83.0 5.30 0.40
3416 海運業 商船三井 3250.0 550.0 1.48 0.63
266 情報・通信業 fonfun 349.0 0.0 46.53 2.07
284 情報・通信業 ASJ 507.0 2.0 67.60 1.62
1912 サービス業 ジェイエスエス 499.0 12.0 6.89 0.74
1606 化学 寺岡製作所 309.0 8.0 19.55 0.26
スポンサーリンク

(パターン3) 利回りが高い順に1銘柄ずつ合計11万円分を購入

BUDGET=110000 # 予算は11万円
row_list = [] # Index格納用
sum_purchase_amount = 0 # 購入金額合計
sum_dividend = 0 # 配当金合計

df2 = df.copy()
df2["利回り"] = df2["配当"] / df2["終値"]

# 利回りの降順でソート
for row in df2.sort_values(by="利回り",ascending=False).itertuples():

    if (BUDGET - row.終値) > 0:
        BUDGET = BUDGET - row.終値
        #print("BUY",row.名称, "BUDGET remain:",BUDGET)
    else:
        #print("skip:",row.名称)
        continue

    sum_purchase_amount = sum_purchase_amount + row.終値
    sum_dividend = sum_dividend + row.配当 + RAKUTEN_HAITO_PROGRAM

    # listにIndexを格納
    row_list.append(row.Index)
# 合計配当金額と合計購入金額と利回りの確認
print(sum_dividend,sum_purchase_amount,sum_dividend/sum_purchase_amount)
Out[0]
8496.2 109995.0 0.07724169280421839
# 結果確認
df[["業種","名称","終値","配当","PER","PBR"]].loc[row_list]
Out[0]

業種 名称 終値 配当 PER PBR
3415 海運業 日本郵船 2947.5 510.0 1.45 0.61
3416 海運業 商船三井 3250.0 550.0 1.48 0.63
3487 海運業 乾汽船 1841.0 173.0 4.95 1.43
3418 海運業 NSユナイテッド海運 3745.0 340.0 3.39 0.66
38 鉱業 三井松島ホールディングス 3055.0 270.0 2.20 0.92
1724 鉄鋼 日本製鉄 2258.5 180.0 3.10 0.52
3417 海運業 川崎汽船 2618.0 200.0 0.99 0.48
89 建設業 西松建設 3930.0 285.0 11.49 1.00
40 鉱業 石油資源開発 4195.0 300.0 4.29 0.57
476 食料品 日本食品化工 2572.0 180.0 5.06 0.55
1672 化学 有沢製作所 1310.0 90.0 13.44 0.91
3730 卸売業 UEX 1024.0 70.0 4.90 0.75
1665 ゴム製品 三ツ星ベルト 3520.0 240.0 14.67 1.11
2552 証券、商品先物取引業 アストマックス 250.0 17.0 4.41 0.56
1614 卸売業 富士興産 1209.0 81.0 17.29 0.84
3076 卸売業 神鋼商事 4485.0 300.0 4.48 0.56
487 食料品 日本たばこ産業 2831.5 188.0 11.04 1.36
2818 小売業 NEW ART HOLDINGS 1509.0 100.0 14.26 2.85
2703 卸売業 伯東 3795.0 250.0 9.02 1.12
103 建設業 淺沼組 2958.0 191.0 11.57 1.13
2596 輸送用機器 タチエス 1143.0 73.6 8.69 0.49
1725 鉄鋼 神戸製鋼所 631.0 40.0 5.53 0.28
95 建設業 奥村組 2978.0 186.0 11.91 0.64
1705 ガラス・土石製品 日本特殊陶業 2670.0 166.0 6.38 0.99
3471 卸売業 オプティマスグループ 854.0 53.0 4.97 0.75
671 不動産業 フージャースホールディングス 776.0 48.0 6.56 0.87
2181 電気機器 東芝 4706.0 290.0 10.71 1.63
1731 鉄鋼 大和工業 4870.0 300.0 4.62 0.71
3087 卸売業 極東貿易 1332.0 81.5 16.40 0.69
3285 証券、商品先物取引業 あかつき本社 311.0 19.0 9.56 0.68
1727 鉄鋼 合同製鐵 1974.0 120.0 4.44 0.28
3504 倉庫・運輸関連業 兵機海運 1894.0 115.0 4.47 0.58
1726 鉄鋼 中山製鋼所 777.0 47.0 4.38 0.44
1884 サービス業 アイ・アールジャパンホールディングス 1875.0 113.0 85.22 5.08
2275 電気機器 日東工業 2330.0 140.0 16.67 0.87
1956 機械 エーワン精密 1666.0 100.0 27.81 0.96
657 不動産業 ディア・ライフ 640.0 38.0 6.85 1.32
2738 小売業 コナカ 338.0 20.0 20.60 0.51
2594 輸送用機器 ティラド 2709.0 160.0 11.77 0.36
1074 化学 片倉コープアグリ 1510.0 89.0 8.45 0.56
655 不動産業 アーバネットコーポレーション 308.0 18.0 7.16 0.75
3533 情報・通信業 コネクシオ 1199.0 70.0 9.41 1.01
1857 金属製品 サンコール 651.0 38.0 13.04 0.50
3278 証券、商品先物取引業 岩井コスモホールディングス 1289.0 75.0 8.90 0.54
3186 銀行業 あおぞら銀行 2647.0 154.0 8.58 0.69
2414 電気機器 アバールデータ 4025.0 234.0 6.06 1.43
3356 不動産業 グランディハウス 551.0 32.0 6.17 0.64
3123 卸売業 三信電気 2328.0 135.0 8.59 0.82
3540 情報・通信業 ソフトバンク 1495.5 86.0 13.09 3.90
3327 不動産業 新日本建物 453.0 26.0 5.81 1.13
3420 海運業 飯野海運 925.0 53.0 5.26 0.92
528 卸売業 ラサ商事 1013.0 58.0 6.66 0.60
2873 精密機器 ノーリツ鋼機 2655.0 152.0 0.91 0.45
2521 サービス業 フォーラムエンジニアリング 885.0 50.0 17.55 2.07
2896 その他製品 KYORITSU 127.0 6.0 6.22 0.66
1834 金属製品 日本パワーファスニング 125.0 5.0 25.00 0.57
3339 不動産業 ランド 10.0 0.1 10.00 2.09
191 サービス業 燦キャピタルマネージメント 17.0 0.0 0.00 2.99
3492 証券、商品先物取引業 アジア開発キャピタル 4.0 0.0 0.00 3.41

利回り重視なので、高めのリターンとなっています

スポンサーリンク

(パターン4) 株価が安い順に1銘柄ずつ合計11万円分を購入

BUDGET=110000 # 予算は11万円
row_list = [] # Index格納用
sum_purchase_amount = 0 # 購入金額合計
sum_dividend = 0 # 配当金合計

# 終値の降順でソート
for row in df.sort_values(by="終値",ascending=True).itertuples():

    if (BUDGET - row.終値) > 0:
        BUDGET = BUDGET - row.終値
        #print("BUY",row.名称, "BUDGET remain:",BUDGET)
    else:
        #print("skip:",row.名称)
        continue

    sum_purchase_amount = sum_purchase_amount + row.終値
    sum_dividend = sum_dividend + row.配当 + RAKUTEN_HAITO_PROGRAM

    # listにIndexを格納
    row_list.append(row.Index)
# 合計配当金額と合計購入金額と利回りの確認
print(sum_dividend,sum_purchase_amount,sum_dividend/sum_purchase_amount)

# 結果確認
df[["業種","名称","終値","配当","PER","PBR"]].loc[row_list]
Out[0]

    6118.51 109635.8 0.05580759204566392
業種 名称 終値 配当 PER PBR
3492 証券、商品先物取引業 アジア開発キャピタル 4.0 0.0 0.00 3.41
3339 不動産業 ランド 10.0 0.1 10.00 2.09
2312 電気機器 ピクセラ 10.0 0.0 0.00 1.82
3328 不動産業 REVOLUTION 15.0 0.0 0.00 3.86
64 建設業 ワイ・ティー・エル・コーポレーション・バーハッド 17.0 0.0 0.00 0.00
... ... ... ... ... ... ...
2210 サービス業 旅工房 401.0 0.0 0.00 0.00
2382 電気機器 小野測器 402.0 5.0 59.11 0.33
1174 化学 積水化成品工業 402.0 12.0 148.88 0.31
2214 サービス業 GameWith 403.0 0.0 45.28 2.22
396 小売業 シー・ヴイ・エス・ベイエリア 403.0 16.0 403.00 0.72

454 rows × 6 columns

454銘柄も買えるようです。配当金プログラムのおかげか、利回りも以外と悪くないです。

スポンサーリンク

(パターン5) 配当金が高い順に1銘柄ずつ合計1万円分を購入

BUDGET=110000 # 予算は11万円
row_list = [] # Index格納用
sum_purchase_amount = 0 # 購入金額合計
sum_dividend = 0 # 配当金合計

# 配当金の降順でソート
for row in df.sort_values(by="配当",ascending=False).itertuples():

    if (BUDGET - row.終値) > 0:
        BUDGET = BUDGET - row.終値
        #print("BUY",row.名称, "BUDGET remain:",BUDGET)
    else:
        #print("skip:",row.名称)
        continue

    sum_purchase_amount = sum_purchase_amount + row.終値
    sum_dividend = sum_dividend + row.配当 + RAKUTEN_HAITO_PROGRAM

    # listにIndexを格納
    row_list.append(row.Index)
# 合計配当金額と合計購入金額と利回りの確認
print(sum_dividend,sum_purchase_amount,sum_dividend/sum_purchase_amount)

# 結果確認
df[["業種","名称","終値","配当","PER","PBR"]].loc[row_list]
Out[0]

    3181.2 109999.0 0.02892026291148101

業種 名称 終値 配当 PER PBR
3051 電気機器 東京エレクトロン 46020.0 1482.0 17.95 4.85
1950 機械 ディスコ 41350.0 900.0 17.98 4.72
2435 電気機器 ファナック 20480.0 558.2 24.56 2.42
3487 海運業 乾汽船 1841.0 173.0 4.95 1.43
655 不動産業 アーバネットコーポレーション 308.0 18.0 7.16 0.75

5銘柄しか購入できない上、そこまでリターンも良くなさそうです。

スポンサーリンク

まとめ

個人的にはやるかどうかは悩み中です。

たくさんの銘柄に分散投資している方がやる分にはいいのではないでしょうか?

1000銘柄に投資している人は配当金プログラム利用で10000円もらえると考えたら悪くない気はします。

タイトルとURLをコピーしました