編集後記「株価が下がったら買いたい? そうだ、スクリプトで試そう!」と「なぜ『Pythonクイズ』なのか?」Deep Insider's Eye 一色&かわさきの編集後記

一色からは「株価が下がったら……」という題でバーゲンセールのように安くなった時に株を購入するインジケーターのスクリプトを作成してシミュレーションしたことについて、かわさきからは「なぜ『Pythonクイズ』なのか?」という題で「なぜ『解決!Python』の代わりに『Pythonクイズ』を始めたのか」──その理由と背景、そして込めた思いについて書きました。

» 2025年01月29日 05時00分 公開
「Deep Insider's Eye 一色&かわさきの編集後記」のインデックス

連載目次

 @ITのDeep Insiderフォーラム【AI・データサイエンスの学びをここから】を担当しているDeep Insider編集部の一色とかわさきです。10月末に公開した編集後記から3カ月ぶりですね。

 編集者が記す「あとがき」である、この編集後記では、執筆/編集時には書けなかった小話や裏話、感想、ぜひ読者にも知ってほしいという話などを書いています。特に今回は、かわさきが書いた「なぜ『Pythonクイズ』なのか?」で、連載を始めた理由と思いが語られています。Pythonに興味のある方は、ぜひご一読いただけるとうれしいです。

株価が下がったら買いたい? そうだ、スクリプトで試そう!(一色)

一色政彦(いっしきまさひこ)

一色 一色政彦

 @ITのDeep Insider編集部の編集長。ロングセラー本『DIE WITH ZERO』を読んで、「経験は資産よりも大事」なので「今しかできないことにお金を使い、思い出を作ることが人生を豊かにする」というメッセージに共感しました。だから今年は、新潟で日本酒を楽しむ旅と、長崎五島列島で『劇映画 孤独のグルメ』のロケ地を巡る旅を計画中です。皆さんも思い出作りに旅に出てみませんか?


 新NISAも2年目。私は今年も楽しむ気で満々です。「つみたて投資枠」と同様に、「成長投資枠」でもオルカンS&P(500インデックス)が人気ですが、私は個別株を“できるだけ安く”買い増したいと考えています。

 できれば株価が下がったタイミングで買い増したいのですが、株価が下がると「明日にはもっと安くなるかも」と不安になり、株価が上がると「今すぐ買わないともっと高くなるかも」と焦ってしまいます。結果的に買い時を逃すことが多いのです。


一色

 豆腐メンタルな私には、買い時を見極める「タイミング投資」や、できるだけ早く投資する「年初一括投資」よりも、資産グラフが右肩上がりになりやすい「毎月積立投資」が向いている気がします。だったら素直にオルカンかS&Pにすればいいじゃん、と思いますよね。でも、それじゃつまらないんです。企業を知ったり応援したりする楽しみも、せっかくなら味わいたいので。



かわさき

 一色さんが豆腐メンタルだとっ……。いつでも自信満々な人だと思っていました(かわさき)。


 本当は「バーゲンセールのように株価を見て、安くなったら逆に買い足す」という購買ルールを順守したいのです。しかし、それを自分の精神力だけで実行するのは難しい。また、常に株価を監視し続けるのも不可能です。そこで、「そうだ、バーゲンセールを自動検知するスクリプトを作ろう!」と思いました。

 私が「バーゲンで購入インジケーター」と呼ぶこのスクリプトは、株価が3%下落した場合に「買い」のシグナルを出し、5%上昇した場合に「売り」のシグナルを出します。ただし、私は長期保有を基本としており、購入した株は基本的に一切売らない予定のため、「売り」シグナルは無視して運用するつもりです。

 また、割高過ぎる時期に買いたくないため、現在の株価が200日移動平均線(長期の平均価格)より高い場合は「買い」シグナルを抑制するようにしました。逆に、割安過ぎる時期に売りたくないため、現在の株価が200日移動平均線より低い場合は「売り」シグナルを抑制します。

 ということで、Web上のチャートツールであるTradingView(トレーディングビュー)用のスクリプトを、ChatGPTに質問しながら作って、それをベースにどれくらいの利益が出るかをシミュレーションで試してみました。ちなみに、昨年も「ゴールデンクロス」と呼ばれる買いシグナルで自動購入する取引スクリプトを作ってバックテストをしましたが、本稿はその続編として、新たなアプローチを試したものです。


一色

 TradingViewには、「Pine」(パイン)という独自のスクリプト言語があります。これを使って、チャート上に描画するインジケーターや、売買戦略を表現するストラテジーを手軽に作成可能です。また、作成したストラテジーを過去の株価データに適用し、「どれくらいの損益になるか」をシミュレーションできるバックテスト機能も完備されています。今回はそのTradingViewの無料版を使用します。


今回紹介する売買シミュレーションはあくまで仮想のものです。この方法を実際の株の売買に適用した場合に生じるいかなる損益や事象に対しても、読者自身の責任で対処していただくようお願いします。筆者や、筆者の所属会社、本情報が掲載されているメディアは、読者自身の行動から生じた結果について一切の責任を負いません。

 今回、私が作成したPineスクリプト(バージョン6)を以下に示します。詳細はソースコード(以下、コード)内のコメントを参考にしてください。ちょっと複雑で長くなったので、難しければコード内容はスルーしてください。コードの後の本文で、気を付けてほしいポイントだけ説明します。

//@version=6
indicator("バーゲンで購入インジケーター", shorttitle="DipSignal", overlay=true)

// [設定]ダイアログにパラメーターとして表示する入力変数
dropPercentage = input.float(3.0, title="価格が何%下落したら買うか", minval=0.1, step=0.1)
risePercentage = input.float(5.0, title="価格が何%上昇したら売るか", minval=0.1, step=0.1)

// 割高判定条件: 現在の価格が200日移動平均線より高い場合は割高と見なす
longTermMA = ta.sma(close, 200// 200日移動平均線
overvalued = close > longTermMA
// 割安判定条件: 現在の価格が200日移動平均線より低い場合は割安と見なす
undervalued = close < longTermMA

// 買いエントリー条件: 2つ前のバーから下降開始し、1つ前と現在のバーを合わせた下落率が○%以上
longCondition = not overvalued and close[2] > close[1] and ((close[2] - close) / close[2]) * 100 >= dropPercentage

// 売りエントリー条件: 2つ前のバーから上昇開始し、1つ前と現在のバーを合わせた上昇率が○%以上
shortCondition = not undervalued and close[2] < close[1] and ((close - close[2]) / close[2]) * 100 >= risePercentage

// プロット: 売買シグナル
plotshape(series=longCondition, title="買いシグナル", text="買", display=display.pane, location=location.belowbar, color=color.aqua, style=shape.labelup)
plotshape(series=shortCondition, title="売りシグナル", text="売", display=display.pane, location=location.abovebar, color=color.orange, style=shape.labeldown)

// プロット: 200日移動平均線
plot(longTermMA, title="200日移動平均線", color=color.new(color.purple, 50), linewidth=4)

「バーゲンで購入インジケーター」を実装したPineスクリプト
このインジケーターは、株価が「設定された下落率(3.0%)」を超えた場合に「買い」シグナル、「設定された上昇率(5.0%)」を超えた場合に「売り」シグナルを表示します。また、割高/割安の判定に200日移動平均線を使用します。

 このスクリプトでは、「買い」「売り」のシグナルとなる「3.0%」「5.0%」という価格変動率の条件を、[設定]ダイアログで簡単に変更できるようにしています。例えば、リスクを抑えたい場合は価格変動率を大きくする、頻繁に売買したい場合は価格変動率を小さくする、といった調整が可能です。

 注意点として、このスクリプトは「日足(ひあし)」か「4時間足」のチャートを使うことを前提としています。日足の場合、3%5%といった価格変動率は、2日分(昨日+今日)のデータで計算されます。4時間足の場合、1日分(午前と午後の2本のバー)のデータで計算されます。TradingViewの画面上部にある時間軸設定から「日足」や「4時間足」など適切な時間軸を選択してください。

 あとは、TradingViewの画面下部の[Pineエディタ]でインジケーターを新規作成して、このスクリプトのコードを貼り付けるだけです。スクリプトを保存すると自動的にコンパイル(=ソースコードが実行可能な形式に変換)されます。その後、[Pineエディタ]の右上にある[チャートを追加]をクリックすると、チャートに[買]や[売]というシグナルが表示されるようになります(図1)。

図1 TradingViewの画面下部にある[Pineエディタ]にスクリプトを貼り付けてチャートに追加したところ 図1 TradingViewの画面下部にある[Pineエディタ]にスクリプトを貼り付けてチャートに追加したところ
紫色の線は、200日移動平均線です。全ての青色の[買]シグナルはこの線より下にあり、全てのオレンジ色の[売]シグナルはこの線より上にあることが分かると思います。

 表示されたシグナルを参考に売買すればよいのですが、「本当に売買すると、損益はどうなるか」が気になります。そこで同じロジックでストラテジーを作ってみました。このストラテジーを実装したPineスクリプトのソースコードは少し長いので、ここでは掲載を省略します。それでも知りたい人のために、説明は行いませんが、本稿の末尾に「おまけ」として掲載しておきます。

 TradingViewの画面下部にある[ストラテジーテスター]でこのストラテジーを読み込むと、トレード履歴や利益の大きさ、勝率などが表示されます(図2)。このストラテジーでは、2024年の1年間中に、予算240万円を使って、株価が安い時に10万円ずつ株を購入します(積立投資と同じ分割投資です)。前提としてミニ株(単元未満株取引)で1株単位で購入できるものとします。

図2 TradingViewの画面下にある[ストラテジーテスター]で成績を確認しているところ 図2 TradingViewの画面下にある[ストラテジーテスター]で成績を確認しているところ
利益の大きさ、勝率などが一目で確認できます。トレード履歴は[トレード一覧]で参照できます。

 図2では、「成長投資枠」の投資先として人気にもかかわらず、株価が低調だったNTT(日本電信電話【銘柄コード:9432】)のシミュレーションを掲載しています。「年初一括投資」だと−9.09%ですが、「安い時に買う分割投資」では+1.34%と何とか黒字です。このように安い時に買っているので、損をしにくいです。

 一方で、「安い時に買う分割投資(や積立投資)」は「年初一括投資」に比べて利益を大きく伸ばしづらい欠点もあります。特に2024年はほとんどの株で上昇が長く続いたため、圧倒的に「年初一括投資」が有利でした。シミュレーションすると、ほとんどの株で「安い時に買う分割投資(や積立投資)」は「年初一括投資」に負けてしまいます。


一色

 これが「年初一括で投資信託を買った方がいい」と主張する人がいる理由だと痛感しました。とはいえ、タイミング投資は確かに難しいですが、それでも挑戦してみたくなるのが投資の面白さですね。



かわさき

 自動売買を実戦投入して、大もうけしたらうまい棒を10本めぐんでください(笑)。結局、株価が上昇トレンドにある現在では年初に買って長期保有が一番良さそうなのね。



一色

 了解です(笑)。でも、完全に自動売買したくても、日本の証券会社(楽天証券やSBI証券など)はTradingViewに対応していないんですよね……と思ったら、ウィブル証券という選択肢があるみたいです。シグナルのメール通知を経由して、auカブコム証券(2025年2月1日に三菱UFJ eスマート証券に社名変更)の「kabu STATION API」で自動売買する方法も考えられますね。とはいえ、最初はシグナルを受け取って、人間が判断して手動売買する方が現実的かもしれません。


 最後に、投資初心者にお薦めの本として『改訂版 本当の自由を手に入れる お金の大学』を紹介します。この本の「STEP 2《増やす》―貯蓄を投資にまわして資産運用しよう―」では、投資の基本が図を多用して分かりやすく、コンパクトにまとめられています。特に、この「STEP 2」のセクションを読むだけで、初心者が必要とする投資の知識を短時間で身に付けられるのが魅力です。

 また、内容は代表的な投資理論を踏襲しており、複数の本を読んで得られる情報が一冊に凝縮されています。投資をこれから始めたい方にぴったりの一冊なので、ぜひ読んでみてください。

なぜ『Pythonクイズ』なのか?(かわさき)

かわさきしんじ

かわさき かわさきしんじ

 大学生時代にIT系出版社でアルバイトを始めて、そのまま就職という典型的なコースをたどったダメ人間。退職しても何か他のことをできるでもなくそのままフリーランスの編集者にジョブチェンジ。そしてDeep Insider編集部に拾ってもらう。お酒とおつまみが大好き。通称「食ってみおじさん」。最近はすっかり「ダイエットおじさん」に変貌したのでした。10月頭には何と! 体重は58kgを割り込んで57kg台に。

 57kg台になったところで、減量期間を終了し、摂取カロリーを2000kcal前後にして、58kg台をキープしていたのですが、年末年始はなかなかそれを守れずにプックリとしました。仕方ないので、そのまま増量期を始めて摂取カロリーもさらに増やして2300kcal前後とした結果、現在では62kg前後の体重となっています。筋肉が付いていればいいんですが、どうも脂肪の方が付きが良いようなので、この後をどうすればよいか、ちょっと悩んでいるところです。



一色

 筋肉を付けるのも難しいですよね。自分の場合は、筋トレの前にまず痩せる必要があるんですが(笑)。最近は、服を着替える前に筋トレする習慣を付けようと、洋服タンスに腹筋ローラーを置いています。それでも無意識にスルーしちゃうんですけど……。完全に余談でした。



かわさき

 痩せる前でも筋トレしちゃっていいという話もあります。筋肉が付く=基礎代謝が上がる=1日の消費カロリーが増えるので痩せやすくなるという話です。とはいえ、痩せるのに一番効くのは「1日の消費カロリー>1日の摂取カロリー」となるように、運動と食事のバランスを考えることなので筋トレとできたら有酸素運動(ぼくはお散歩しかしていません)を生活に取り入れて、食べ過ぎに注意するのが一番ですよ。


 Deep Insiderの初期から続けてきた「解決!Python」に代わる連載をどうするか? という話については、この編集後記でも何度か話題にしてきました。そして、2024年の11月から始まったのが「Pythonステップアップクイズ」(略して「Pythonクイズ」)です。今回は記憶を掘り起こしながら、なんでまたクイズになったのか? その裏話をしてみたいと思います。

 解決!Pythonに代わる連載をどうしよう? という話は「知識(TIPS)をサイト内に蓄積して、読者がWeb検索でそれらにアクセスしてくれることを前提としたコンテンツ(とはまさに解決!Pythonのことです)の先行きが、生成AIの登場によって見えなくなってきたね」という意見が編集会議で出てきたのを発端としています。つまり、以下のようなことが原因で、解決!Pythonのようなコンテンツはそろそろ寿命がやってきているのではないか? ということです。

  • プログラミングをしている際のちょっとした問題の解決に、Webベースあるいは開発環境やエディタに統合されたチャットボットを利用することが多くなり、Web検索でのコンテンツへの流入が減少する

 実際、2024年にはそうした動きが顕著に見られました。検索ランクでは上位にいるコンテンツであってもページビューが右肩下がりで減少しているのです。例えば、「python yyyymmdd」でGoogle検索すると、解決!Pythonの「日付や時刻をYYMMDDhhmmssなどの形式に書式化するには」が検索結果の比較的上位の位置に表示されると思います。

「python yyyymmdd」でGoogle検索した結果(パーソナライズの影響を受けないようにプライベートモードで検索したもの) 「python yyyymmdd」でGoogle検索した結果(パーソナライズの影響を受けないようにプライベートモードで検索したもの)

 その一方で、このコンテンツの2024年のページビューの推移がどうなっているかを示したものが以下です。

右肩下がりのページビュー 右肩下がりのページビュー

 検索ランクでは上位をキープしていても、見事なくらいに右肩下がりになっていることが分かります。

 TIPS記事はWeb検索でたどり着き、自分の役に立つコードをコピー&ペーストし、必要なら書き換えるというのがその主要な使われ方でしょう。しかし、チャットボットであれば、変数名やその他のコンテキストについても考慮したコードが自動で生成されます。しかも、それが開発環境やエディタに統合されていたなら、わざわざウィンドウや自分の意識をWebブラウザに切り替える必要がありません。となれば、このような記事の需要が減少していくのは当たり前です。

 こうなることを2024年の割と早い時期から編集部では想像していて、じゃあどうするんだ? という話し合いが続けられました。その中では、次のような連載企画案が出てきました(以下はこんな内容というだけで、連載タイトル案とは違います)。

  • 生成AIと学ぶPythonプログラミング
  • 思った結果を得るためのプロンプトTIPS
  • 生成AIによって作られたダメなコードを修正してみよう

 うん。生成AIを活用したコンテンツがどんなものになるかを考えて、悪戦苦闘している感がありますね。でも、生成AIの進化の速度を考えると、こうしたコンテンツは陳腐化するのも速いだろうと編集部では判断しています(また、記事と同じことを試したときに、同じ結果を読者が得られないのもあまりよろしくない点として考えられました)。

 ここで「生成AIと絡めたコンテンツ」という観点から離れて、読者のことを考えてみましょう。読者がDeep Insiderというサイト(フォーラム)を信頼して、固定のお客さんとなってくれるにはどうしたらよいかです。以前なら、Web検索でDeep Insiderの記事にアクセスすることが何度かあれば、「ここイイね!」となってくれるだろうと考えられました。

 「ここイイね!」と思ってもらえるような良質なコンテンツを提供することに変わりはありません。これからもそうした記事を提供していけるように、編集部一同が努力していこうと思っています。では、どうすれば「ここイイね!」と思ってもらえるのでしょうか。良質なコンテンツだけではない何かをプラスアルファとして用意する必要があるのではないでしょうか。しかも、生成AIではできそうもない何かです。

 そうした何かの候補の一つとして考えられたのが「個人の考えの発露」です。HPかわさきというキャラクターを作ったのも、X(旧Twitter)で筆者個人が何かを伝えていくことで、筆者自身ひいてはDeep Insiderを身近な存在として感じ、記事とポストを見て信頼してもらえたらいいなという考えがあります。

 さらに「読んでいて楽しい」というのも個人的には重要な要素だと考えています。生成AIから離れてPythonについてのクイズにしたのはそうした点も考えてのことです。読者参加型の記事というほどのものではありませんが、通勤/通学の途中でクイズを目にして「お? これはこんなふうにすれば解けるんじゃないの?」と考えてもらう、記事を読み進めると「思いの外、いろいろと知識が得られた」と感じてもらう、それだけでも記事の内容に読者が参加してくれるものだと筆者は考えています(できれば、Xのアカウントにメンションなどあるとうれしいのですが、きっとお相手をするほどの余裕はありません。でも、記事制作の参考にはなるはずです)。


一色

 そうそう。毎週火曜日の朝、「通勤/通学の途中」の5分くらいを使って、Pyトレ(Pythonトレーニング)の時間にしてもらえたらうれしいなと思っています。私が書いた筋トレの余談のように、読者の皆さんにもそれを習慣化してほしい、というのも狙いの一つです。そして、気づけば「いつの間にかPythonスキルが上がっていた」となれば最高ですよね!


 Pythonクイズは解決!Pythonのような知識蓄積型の記事ではなく、Web検索からの読者流入もあまり考えていません。その代わりにGoogleニュースやGoogle Discoveryで読者の皆さんの目に触れられればいいなと考えていて、実際の読者の傾向もそのようになっています。当面はこの連載を続けていきながら、皆さんに楽しみながらPythonの知識を身に付けてもらったり、自分がちゃんと分かっていることを確認してもらったりできればいいなと考えています。

 というわけで、Pythonクイズをこれからもよろしくお願いいたします。


かわさき

 意外に長くなってしまいました。しかも、記憶を掘り起こしながら原稿を書いているので、一色さんの認識とは違っているかもしれません。が、まあ、だいたいこんな感じのことを考えて始まったという裏話でした。



一色

 同じ認識です! Pythonクイズはページビューも安定して多く、「うまくいっている」と感じています。身内のチームながら、Pythonクイズのファンがこれからもっと増えていくのを楽しみにしています。読者の皆さんも、各クイズで何か思うことがあれば、ぜひSNSでお気軽にコメントをいただけると参考や励みになります!


おまけ:「バーゲンで購入ストラテジー」のコード内容(一色)

 コードの意味が分からないときは、ChatGPTなどのチャットAIに1行ずつ質問してみるのがお勧めです。

//@version=6
strategy("バーゲンで購入ストラテジー", shorttitle="DipBuy", initial_capital=2400000, overlay=true, fill_orders_on_standard_ohlc=true, pyramiding=1000)

// 【シミュレーション】年間予算(円)
annualBudget = 2400000

// [設定]ダイアログにパラメーターとして表示する入力変数
startYear = input.int(2024, title="【シミュレーション】開始年", minval=2000, step=1)
startMonth = input.int(1, title="【シミュレーション】開始月", minval=1, maxval=12, step=1)
purchaseLimit = input.int(100000, title="【シミュレーション】1回の購入上限(円)", minval=10000, step=10000)
dropPercentage = input.float(3.0, title="【シグナル】 価格が何%下落したら買うか", minval=0.1, step=0.1)
risePercentage = input.float(5.0, title="【シグナル】価格が何%上昇したら売るか", minval=0.1, step=0.1)

// シミュレーション期間の自動設定
startDate = timestamp(startYear, startMonth, 1, 0, 0// 開始日を指定
endDate = timestamp(startYear + 1, startMonth, 1, 0, 0) - 1  // 終了日を1年後の月末に設定

// 割高判定条件: 現在の価格が200日移動平均線より高い場合は割高とみなす
longTermMA = ta.sma(close, 200// 200日移動平均線
overvalued = close > longTermMA
// 割安判定条件: 現在の価格が200日移動平均線より低い場合は割安
undervalued = close < longTermMA

// 買いエントリー条件: 2つ前のバーから下降開始し、1つ前と現在のバーを合わせた下落率が○%以上
longCondition = not overvalued and close[2] > close[1] and ((close[2] - close) / close[2]) * 100 >= dropPercentage

// 売りエントリー条件: 2つ前のバーから上昇開始し、1つ前と現在のバーを合わせた上昇率が○%以上
shortCondition = not undervalued and close[2] < close[1] and ((close - close[2]) / close[2]) * 100 >= risePercentage

// 購入処理
var float remainingBudget = annualBudget  // 残り予算
if longCondition and time >= startDate and time < endDate
    maxShares = math.floor(math.min(purchaseLimit, remainingBudget) / close)
    if maxShares > 0 and remainingBudget >= close * maxShares
        strategy.entry("Buy", strategy.long, qty=maxShares)
        remainingBudget -= close * maxShares

// 年初一括購入時の価格を保存
var float startPrice = 0.0
var bool savedStartPrice = false
if not savedStartPrice and time >= startDate
    startPrice := close
    savedStartPrice := true

// シミュレーション終了日に全ポジションを売却
var bool isClosed = false
if not isClosed and time >= endDate and strategy.position_size > 0  
    strategy.close("Buy", comment="Final Close", immediately=true)
    isClosed := true

    // 買い足し購入した場合の資産増減率(%)
    finalCapital = strategy.equity  // 最終資産
    initialCapital = strategy.initial_capital  // 初期資産
    capitalGainRate = (finalCapital - initialCapital) / initialCapital * 100

    // 年初に購入した場合の資産増減率の計算
    endPrice = close  // 終了日の価格を保存
    singleBuyGainRate = 0.0
    if startPrice != 0.0
        singleBuyGainRate := (endPrice - startPrice) / startPrice * 100  // 年初一括購入した場合の資産増減率(%)

    // チャート上に情報表示
    comparison = "総資産増減率: " + str.tostring(capitalGainRate, "#.##") + "%\n" +
                 "年初一括購入: " + str.tostring(singleBuyGainRate, "#.##") + "%\n" +
                 "(買値: " + str.tostring(startPrice, "#.##") + ", 売値: " + str.tostring(endPrice, "#.##") + ")"
    label.new(bar_index, low*0.8, comparison, style=label.style_label_up, color=color.new(color.black, 50))

「バーゲンで購入ストラテジー」を実装したPineスクリプト

「Deep Insider's Eye 一色&かわさきの編集後記」のインデックス

Deep Insider's Eye 一色&かわさきの編集後記

Copyright© Digital Advantage Corp. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。