これまでの経緯
本記事は、Pythonによる株式スクリーニング自動化・実践の続編です。これまでの背景や検証の流れは、以下の記事をご確認ください。
はじめに
前回は、生成AIを活用して株価スクリーニングBotを作る-中編として、スクリーニング結果の可視化やX APIを用いたX(旧Twitter)への投稿までの流れを紹介しました。
これで、完全bot化ができた!と言いたいところですが、肝心なことを忘れてしまっています。
それは、「毎日+自動で」という部分です。
仕事終わりに、自分のXを見たら、抽出銘柄が勝手にお知らせされてるようにするには、
Cursorの実行ボタンも
VSCodeの実行ボタンも
PyCharmの実行ボタンも
Colabの実行ボタンも
どこも押さずに、コードが実行されていないと意味がありません。
今回は、macOSに標準搭載されている「Cron」という便利な機能を使って、Pythonスクリプトを自動実行する方法を紹介します。
これで、仕事終わりの疲れた脳でも、お布団に吸引されずに、投資を続けられる…はずです。
Cron設定前の準備
設定を始める前に、3つの大事な情報を確認・準備しておきます。
1. Pythonスクリプトのパスを確認する
動かしたいPythonファイル(例: auto_tech_screening_and_notify.py
)がMacのどこにあるか、正確なフルパスを調べておきます。
例: /Users/あなたのユーザ名/PycharmProjects/pythonProject/auto_tech_screening_and_notify.py
CursorやVS CodeなどのIDEを使っている場合: IDEでプロジェクトを開くと、左側のサイドバーなどにファイル構造が表示されます。あなたのPythonスクリプトがその中でどこにあるかを確認し、その場所からフルパスを特定してください。 例: /Users/あなたのユーザ名/Documents/MyStockBot/auto_tech_screening_and_notify.py
(CursorやVS Codeでのプロジェクトパスの例)
それも面倒なとき: AIエディタをご使用の場合は、開いているpythonファイルをチャット欄にドラッグドロップして、これのディレクトリ教えてと要求します。大体正しいディレクトリが返ってきます。
2. Pythonインタープリタのパスを確認する
スクリプトを実行するPython本体(Anacondaの仮想環境で作ったPythonなど)がどこにあるか、正確なフルパスを確認します。
Anaconda仮想環境の場合:
ターミナルで仮想環境をアクティブにした状態で which python
または which python3
と入力するのが簡単です。例: /Users/あなたのユーザ名/opt/anaconda3/envs/env3/bin/python3
Cursor / VS Codeなどでプロジェクト内に仮想環境を作成している場合:
これらのIDEは通常、プロジェクトフォルダ内に仮想環境(例: venv
フォルダ)を作成します。その場合、パスは以下のようになります。
例: /Users/あなたのユーザ名/Documents/MyProject/venv/bin/python
(プロジェクトのルートフォルダにある venv
フォルダ内の bin/python
です)
PyCharmの場合:
PyCharm → Settings (または Preferences) → Project: [プロジェクト名] → Python Interpreter で表示されるパスを確認できます。
それも面倒なとき: 使っているIDEがAI機能を持っている場合、「このプロジェクトで使っているPythonインタープリタのパスを教えて」とAIに聞くと大体、正しいパスが返ってきます。たまに大嘘を丁寧に教えてくれることがありますが。
3. ログ保存用のフォルダを作る
Cronは画面に何も表示しません。実行結果やエラーを確認するためにログファイルが必須です。ログを保存するフォルダを先に作っておきます。
ターミナルで次のコマンドを実行します。
mkdir -p /Users/あなたのユーザ名/your_project_path/logs
(ログフォルダのパスは、スクリプトのパスに合わせて適宜変更してください。例: /Users/あなたのユーザ名/Documents/MyProject/logs
)
Cronの設定手順
準備が整ったら、いよいよCronジョブをMacに登録します。
1. ターミナルを開く
「アプリケーション」→「ユーティリティ」→「ターミナル.app」を起動します。
2. crontab エディタを開く
ターミナルで次のコマンドを打ち込み、Enterキーを押します。
ポイント: ここで開くエディタは、Macの設定で変わります。
- vi: 操作が少し特殊ですが、ここではviの使い方を示します。
- nano: シンプルで使いやすいエディタです。
3. Cronジョブを書き込む
crontab -e
で開いたエディタに、以下の内容をコピーして貼り付けます。
これは「平日18:30にテクニカルスクリーニングスクリプトを実行」する設定です。
# 平日実行用cron設定
# 環境変数設定(APIキーをここに貼るのはまずいけど、とりあえずはこれで動く)
TWITTER_API_KEY="your_api_key_here"
TWITTER_API_SECRET="your_api_secret_here"
TWITTER_ACCESS_TOKEN="your_access_token_here"
TWITTER_ACCESS_TOKEN_SECRET="your_access_token_secret_here"
# テクニカルスクリーニングスクリプト - 平日18:30に実行
40 18 * * 1-5 /Users/あなたのユーザ名/opt/anaconda3/envs/your_env/bin/python3 /Users/あなたのユーザ名/your_project_path/auto_tech_screening_and_notify.py >> /Users/あなたのユーザ名/your_project_path/logs/auto_tech_screening.log 2>&1
Cronの時刻設定について
cronの時刻設定は 分 時 日 月 曜日
の順番で指定します:
40 18 * * 1-5
│ │ │ │ │
│ │ │ │ └── 曜日(1-5 = 月曜日から金曜日)
│ │ │ └──── 月(* = 毎月)
│ │ └────── 日(* = 毎日)
│ └──────── 時(18 = 18時 = 午後6時)
└────────── 分(40 = 40分)
各フィールドの詳細:
フィールド | 範囲 | 説明 |
---|---|---|
分 | 0-59 | 0分から59分 |
時 | 0-23 | 0時(深夜)から23時 |
日 | 1-31 | 1日から31日 |
月 | 1-12 | 1月から12月 |
曜日 | 0-7 | 0,7=日曜日、1=月曜日、2=火曜日…6=土曜日 |
特殊文字の使い方:
-
*
= すべての値(毎分、毎時、毎日など) -
*/n
= nおき(*/15 = 15分おき) -
,
= 複数の値を指定(1,3,5 = 1,3,5番目) -
-
= 範囲指定(1-5 = 1から5まで) -
?
= 日または曜日で「どちらでもよい」を表す(日と曜日は同時に指定不可)
よく使う時刻設定例:
-
0 9 * * 1-5
→ 平日の9:00に実行 -
30 18 * * 1-5
→ 平日の18:30に実行 -
0 0 * * *
→ 毎日0:00(深夜)に実行 -
0 */2 * * *
→ 2時間おきに実行 -
*/15 * * * *
→ 15分おきに実行 -
0 9,18 * * 1-5
→ 平日の9:00と18:00に実行 -
0 9 * * 1,3,5
→ 月・水・金の9:00に実行
コマンドの各部分の説明
40 18 * * 1-5 /Users/あなたのユーザ名/opt/anaconda3/envs/your_env/bin/python3 /Users/あなたのユーザ名/your_project_path/auto_tech_screening_and_notify.py >> /Users/あなたのユーザ名/your_project_path/logs/auto_tech_screening.log 2>&1
コマンドの構成要素:
部分 | 説明 | 例 |
---|---|---|
40 18 * * 1-5 |
cronの時刻設定 | 平日18:40に実行 |
/Users/あなたのユーザ名/opt/anaconda3/envs/your_env/bin/python3 |
Pythonインタープリタのフルパス | 仮想環境のPython |
/Users/あなたのユーザ名/your_project_path/auto_tech_screening_and_notify.py |
実行するPythonスクリプトのフルパス | メインスクリプト |
>> |
リダイレクト(追記) | ログファイルに追加 |
/Users/あなたのユーザ名/your_project_path/logs/auto_tech_screening.log |
ログファイルの保存先 | 実行ログの保存場所 |
2>&1 |
エラー出力のリダイレクト | エラーも同じログファイルに保存 |
リダイレクト記号の違い:
-
>
= 上書き(既存のログを消して新しいログで置き換え) -
>>
= 追記(既存のログに新しいログを追加) -
2>&1
= 標準エラー出力(2)を標準出力(1)にリダイレクト
ログファイルの重要性:
Cronは画面に何も表示しないため、ログファイルがないと実行結果やエラーが分かりません。ログファイルを推奨します。
【重要】この方法のセキュリティ上の注意点:
この方法では、APIキーがcrontabファイルに直接記述されます。crontabファイルは、そのユーザーであれば誰でもcrontab -l
コマンドで内容を見ることができます。
もしPCが他人に操作されたり、ファイルが意図せず公開されたりした場合、APIキーが漏洩する高いリスクがあります。
.env
ファイルを別途作成して、それを参照するやり方でやろうしたのですが、なぜか、参照できないエラーが出ます。有識者の方、対処法ご教示いただけないでしょうか。この部分は対策が分かり次第、加筆修正します。
4. 保存してエディタを閉じる
viの場合: Esc
を押し、:
(コロン) を入力し、wq
と入力してEnter。
ターミナルに crontab: installing new crontab
と出ればOKです。
祝日のスキップ設定(Pythonスクリプトの修正)
Cronは土日を避けられますが、日本の祝日は分かりません。なので、スクリプト内で祝日かどうかを判定し、祝日なら処理を中止するようにします。
例えば下記のようなPythonスクリプトの冒頭(日付設定のすぐ後)に、挿入すると良いと思います。jpholiday
ライブラリが必要です。
import jpholiday
# --- 祝日なら処理をスキップ ---
if jpholiday.is_holiday(PREDICTION_TARGET_DATE):
print(f"⚠️ 本日 {PREDICTION_TARGET_DATE.strftime('%Y-%m-%d')} は祝日のため、処理をスキップします。")
import sys
sys.exit()
# ... (以降の処理は祝日でなければ動きます) ...
最終チェック
Macのスリープ設定:
システム設定 → ディスプレイ → 詳細 (または 省エネルギー) で、「電源アダプタ使用時は、ディスプレイがオフの時にコンピュータを自動でスリープさせない」にチェックが入っているか確認します。
MacBookを使っているなら、外部ディスプレイと電源をつないでクラムシェルモードにすれば、蓋を閉じたまま動かせます。
常にスリープさせない設定(ターミナルコマンド):
より確実にMacをスリープさせたくない場合は、以下のコマンドをターミナルで実行します。
sudo pmset -a disablesleep 1
このコマンドは、Macが電源アダプタに接続されているかバッテリー駆動であるかにかかわらず、スリープを無効にします。sudo
は管理者権限でコマンドを実行するためのものです。パスワードの入力が求められる場合があります。
スリープを有効に戻す場合:
スリープを有効に戻したい場合は、以下のコマンドを入力します。
sudo pmset -a disablesleep 0
寿命が縮みそうなので、筆者はメイン機とは別の、おじいさんMacで実行しています。おそらくソフマップ行きがなくなったから喜んでいると思います。メルカリ行きは検討中ですが…
Google Driveへのアクセス許可:
macOS Montereyなどの古いOS環境で、CronがGoogle Drive同期フォルダにアクセスする際に「アクセス権限がない」と怒られる場合、以下の手順でCronにフルディスクアクセスを許可する必要があります。
- 「システム環境設定」→「セキュリティとプライバシー」→「プライバシー」タブを開きます。
- 左側のリストから「フルディスクアクセス」を選択します。
- 鍵のアイコンをクリックしてロックを解除し、管理者パスワードを入力します。
- リストの下にある「+」ボタンをクリックします。
- ファイル選択ダイアログで
Command + Shift + G
を押し、「フォルダへ移動」の入力欄に/usr/sbin/cron
と入力してEnterキーを押します。 - 表示されたcronを選択し、「開く」をクリックします。
- リストにcronが追加され、チェックが入っていることを確認します。
- 鍵のアイコンを再度クリックしてロックします。
この設定により、CronがGoogle Drive内のファイルにアクセスできるようになります。
引用: macOS Catalinaでcrontab -e でOperation not permittedの解消方法
J-Quantsなど認証情報の管理:
セキュリティのため、メールアドレスとパスワードをコードに直接書かず、環境変数などで管理することを強くおすすめします。
Cron設定の確認と監視
設定後、crontab -l
で登録したジョブが表示されるか確認できます。
スクリプトが動く時間になったら、設定したログファイル(auto_tech_screening.log
)を見て、正常に動いたか、エラーは出ていないかを確認できます。
ログの確認方法:
ログを見る:
cat /Users/あなたのユーザ名/your_project_path/logs/auto_tech_screening.log
最新の行だけ見る(リアルタイム監視も可能):
tail -f /Users/あなたのユーザ名/your_project_path/logs/auto_tech_screening.log
(Ctrl + C
で監視を終了します。)
実際に運用している様子
以下は、このBotが実際にXに投稿しているところを、
筆者が、実況解説している様子です。
これで、毎日つぶやくことがなくても、とりあえずネタがあるようにはなります。
あ、そちらが目的ではなかったですね。
このようなbot化により、
きっとあなたも仕事終わりに、お布団に吸引されずに、投資を続けることができるようになると思います。
まとめ
今回は、MacのCronを使ってPythonスクリプトを自動実行する方法を紹介しました。
これで、銘柄スクリーニングBotは、土日祝日を除く平日の毎日、決まった時間に自動で動くようになります(約1週間は動作確認済み)
APIキーをcrontabに直接記述する方法は手軽ですが、セキュリティ上のリスクがあることを理解し、将来的な改善を検討することをお勧めします。
自動化によって、日々の作業がぐっと楽になり、仕事終わりの時間をもっと有効に使えるようになると良いですね。
いいえ、結局選抜された銘柄の中から、本当に有望なやつを選ぶ作業が待っているので、どんどん投資沼にハマっていくことになるのです。
楽して稼ぐ方法なんてあるわけないじゃないですか。
いやー、7/14までに終わらなかったら、Qiita休止宣言しましたが、結局、期限内に終わってしまいましたね。これで、しばらくお休みをいただ…
今回の活動を通して、ChatGPTはしばらく解雇して、Google GeminiとCursorの有料版を雇い始めました。やっぱり無料期間を最初に体験させてもらうと、結局契約してしまします。意志が弱い。しばらく使ってみます。
次回の予告
毎日の自動運用ができるようになったのは良いのですが、今の状態だとGoogleドライブやローカルのフォルダに、毎日のスクリーニングの結果が溜まっていきます。後から、あの時ヒットした銘柄はどれですか?と知りたくなっても、フォルダーを検索するのって手間がかかりませんか?
そこで現在、誠意検討中なのは、毎日の運用で溜まるデータがをデータベースにできないか?ということです。ローカルやドライブにcsvやparquetで保存するのは、一見良いのですが、大規模なバックテストや機械学習をする時に、それらのファイルを参照してやるのが面倒な気がしてきました。
そんなこんなで、MySQLでも触ってみてどんな感じか確かめる記事を書いてみようと思います。決して、Qiita Tech Festa 2025 スタンプラリーを制覇したいわけじゃありませんよ。
参考リンク
Views: 0