
こんにちは、株道経済研究所です。
皆さんは毎日のデイトレードの銘柄選定、どうやっていますか? 移動平均線のゴールデンクロス? RSIの売られすぎ? それとも出来高急増ランキング?
世の中にはたくさんのスクリーニングツールがありますが、僕は常々、ある強い不満を抱えていました。
「自分の欲しい『ローソク足の形』を、ピンポイントで抽出できるツールがなかなかない……!」
「下ひげピンバー」や「大陽線」といったプライスアクション(値動き)こそ、デイトレの命。それなのに、既存のツールはインジケーター(指標)ばかりで、形状に特化したものがなかなか見つかりません。
――無いなら、作るしかない。
今回は、Pythonを使って自作した、僕専用の「ローソク足形状特化スキャナー」の開発舞台裏をお届けします。
1.ローソク足の形でスクリーニングができない!
僕がデイトレの銘柄選びで最も重要視しているのは、ローソク足の形状です。
人それぞれデイトレの戦略は違うと思いますが、僕の場合は「大陽線」「大陰線」や「下ひげピンバー」の形から翌日のデイトレ銘柄を選別していきます。
しかし、いざ銘柄を探そうとすると大きな壁にぶつかります。
ターゲットを日経225銘柄に絞ったとしても、何百ものチャートを1つずつ手動でチェックする時間は当然ありません。そこで証券会社のスクリーニング機能を使うわけですが、用意されているのは「移動平均線」や「RSI」といったテクニカル指標ばかり。「前日が下ひげピンバーの銘柄」といった、ピンポイントな形状指定はほぼ不可能です。
ローソク足の形状検索ができる専門サイトも一部ありますが、
- データの更新時間を待つ必要がある
- 検索条件の自由度が低く、自分好みの微調整ができない
- UIが使いづらい
といった不満があり、
「既存のツールが使えないなら、自分の手で理想のシステムを組むしかない」
これが、今回Pythonを使ったチェッカー自作に踏み切った理由です。
2. 環境構築
開発環境は、僕もお気に入りの Visual Studio Code(VS Code) を使っています。
もしPCにPythonが入っていなければ、まずは公式サイトからインストールを済ませておいてください。
⚠️ Windowsユーザーへの注意点 インストーラーを起動した際、画面下部にある 「Add python.exe to PATH」 というチェックボックスに必ずチェックを入れてからインストールを進めてください。これにチェックを入れ忘れると、この後の作業でエラーになってしまいます。
必要なライブラリのインストール手順
プログラムを動かすために必要な外部ライブラリは、実は2つだけです。「黒い画面(ターミナル)とか触ったことない…」というプログラミング初心者の方も、以下の手順通りにやれば一瞬で終わります!
- 画面を開く
- Windowsの方: スタートメニュー(画面左下の虫眼鏡マーク)で「cmd」と検索し、コマンドプロンプトを開きます。
- Macの方: アプリケーション一覧の「ユーティリティ」フォルダの中にある、またはSpotlight検索で「ターミナル」と検索してターミナルを開きます。
- コマンドをコピペして実行する 開いた黒い画面に、以下の文字をそのままコピー&ペーストして、キーボードのエンターキー(Enter)をポンッと押してください。
Bash
pip install yfinance pandas
画面に文字がダダダッと流れて、最後に Successfully installed... と出れば準備完了です!
今回導入したライブラリは、それぞれこんな魔法のような役割を持っています。
- yfinance: Yahoo! Financeから過去の株価データを無料で一括ダウンロードできるライブラリ。
- pandas: 大量の株価データをテーブル形式で超高速に計算・処理するライブラリ。
3. 完成したコード(コピペOK)
ここからは実際のコードを公開します! 今回は、管理がしやすいようにプログラムを2つのファイルに分けて作成しました。
まずは、スキャン対象となる日経225の銘柄リストを管理するファイルから作っていきます。プログラムは2つのファイルに分けて管理します。同じフォルダに保存して実行してください。
① 銘柄リスト用ファイル:nikkei.py
yfinanceの仕様に合わせるため、4桁の証券コードの後ろに自動で .T (東京証券取引所の意味)を付与する形にしています。
(※ちなみに銘柄名を入れるのは面倒だったので、コードだけにしました💦 もし「4151」の後に「協和キリン」と名前を付けたい場合や、グロース・スタンダードの銘柄を増やしたい場合は、リストの中にどんどん追加していけば大丈夫です!)
以下のコードを丸ごとコピーして、nikkei.py という名前で保存してください。
# nikkei.py
# 日経225構成銘柄リスト
def get_nikkei225():
stocks = [
"4151",
"4502",
"4503",
"4506",
"4507",
"4519",
"4523",
"4568",
"4578",
"285A",
"4062",
"6479",
"6501",
"6503",
"6504",
"6506",
"6526",
"6645",
"6701",
"6702",
"6723",
"6724",
"6752",
"6753",
"6758",
"6762",
"6770",
"6841",
"6857",
"6861",
"6902",
"6920",
"6954",
"6963",
"6971",
"6976",
"6981",
"7735",
"7751",
"7752",
"8035",
"543A",
"7201",
"7202",
"7203",
"7211",
"7261",
"7267",
"7269",
"7270",
"7272",
"4543",
"4902",
"6146",
"7731",
"7733",
"7741",
"9432",
"9433",
"9434",
"9984",
"5831",
"7186",
"8304",
"8306",
"8308",
"8309",
"8316",
"8331",
"8354",
"8411",
"8253",
"8591",
"8697",
"8601",
"8604",
"8630",
"8725",
"8750",
"8766",
"8795",
"1332",
"2002",
"2269",
"2282",
"2501",
"2502",
"2503",
"2801",
"2802",
"2871",
"2914",
"3086",
"3092",
"3099",
"3382",
"7453",
"7532",
"8233",
"8252",
"8267",
"9843",
"9983",
"2413",
"2432",
"3659",
"3697",
"4307",
"4324",
"4385",
"4661",
"4689",
"4704",
"4751",
"4755",
"6098",
"6178",
"6532",
"7974",
"9602",
"9735",
"9766",
"1605",
"3401",
"3402",
"3861",
"3405",
"3407",
"4004",
"4005",
"4021",
"4042",
"4043",
"4061",
"4063",
"4183",
"4188",
"4208",
"4452",
"4901",
"4911",
"6988",
"5019",
"5020",
"5101",
"5108",
"5201",
"5214",
"5233",
"5301",
"5332",
"5333",
"5401",
"5406",
"5411",
"3436",
"5706",
"5711",
"5713",
"5714",
"5801",
"5802",
"5803",
"2768",
"8001",
"8002",
"8015",
"8031",
"8053",
"8058",
"1721",
"1801",
"1802",
"1803",
"1808",
"1812",
"1925",
"1928",
"1963",
"5631",
"6103",
"6113",
"6273",
"6301",
"6302",
"6305",
"6326",
"6361",
"6367",
"6471",
"6472",
"6473",
"7004",
"7011",
"7013",
"7012",
"7832",
"7911",
"7912",
"7951",
"3289",
"8801",
"8802",
"8804",
"8830",
"9001",
"9005",
"9007",
"9008",
"9009",
"9020",
"9021",
"9022",
"9064",
"9147",
"9101",
"9104",
"9107",
"9201",
"9202",
"9501",
"9502",
"9503",
"9531",
"9532",# ここに日経225コードを追加
]
return [
code + ".T"
for code in stocks
]
if __name__ == "__main__":
stocks = get_nikkei225()
print("日経225銘柄数:", len(stocks))
for stock in stocks:
print(stock)
もし銘柄名も一緒に管理したい場合の書き方
Python
def get_nikkei225_with_names():
# 「コード: 銘柄名」のペアで管理する
stocks = {
"4151": "協和キリン",
"4502": "武田薬品工業",
"4503": "アステラス製薬",
# ...こんな風に並べていく
}
# yfinance用に ".T" を付けたコードと、名前をセットにして返す
return {code + ".T": name for code, name in stocks.items()}
② メインプログラム:scanner.py
準備が整ったら、いよいよローソク足の形状を自動判定する本丸のプログラムを作ります。
このプログラムでは、僕の欲しいローソク足の形状(大陽線、大陰線、長い下ヒゲ)がスクリーニングできるようにしています。
このプログラムの最大の特徴は、「過去60日間のローソク足の平均サイズ」をベースに計算している点です。銘柄によってボラティリティ(値動きの大きさ)は全く違いますよね。一律で「〇〇円以上の値幅」と決めるのではなく、「その銘柄の普段のサイズの2倍以上」を自動で計算して「大陽線」と判定する、ロジックを組みました。
以下のコードを丸ごとコピーして、先ほどと同じフォルダに scanner.py というファイル名で保存してください。
Python
# scanner.py
# 日経225 ローソク足スキャナー
import pandas as pd
import yfinance as yf
from nikkei import get_nikkei225
# ==========================
# 設定(3ヶ月ベースに最適化)
# ==========================
BODY_AVG_DAYS = 60 # 実体平均(日数):3ヶ月(約60営業日)
BIG_BODY_RATE = 2.0 # 大陽線・大陰線(平均の2倍以上)
MIN_BODY_RATE = 0.3 # 小さすぎる実体を除外(大陽線・大陰線用)
BOUZU_RATE = 0.05 # 坊主判定(ヒゲ5%以下)
# ==========================
# ローソク足判定
# ==========================
def judge_candle(df):
result = []
# データ不足
if df.empty or len(df) < BODY_AVG_DAYS:
return result
# MultiIndex対策
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0)
# コピーを作成
df = df.copy()
# 実体サイズ
df["Body"] = (df["Close"] - df["Open"]).abs()
# 過去60日平均(3ヶ月)
df["AvgBody"] = df["Body"].rolling(BODY_AVG_DAYS).mean()
# 最新行
row = df.iloc[-1]
avg_body = float(row["AvgBody"])
# 平均が計算できていない
if pd.isna(avg_body):
return result
open_price = float(row["Open"])
high = float(row["High"])
low = float(row["Low"])
close = float(row["Close"])
body = float(row["Body"])
upper_wick = high - max(open_price, close)
lower_wick = min(open_price, close) - low
total_range = high - low
# ゼロ除算対策と、値動きが全くない日は除外
if total_range <= 0:
return result
# ==========================
# 強い陽線(高値引け)
# ==========================
if (
close > open_price
and body >= avg_body * BIG_BODY_RATE
and upper_wick <= total_range * BOUZU_RATE
):
result.append("大陽線(高値引け)")
# ==========================
# 大陰線(安値引け)
# ==========================
if (
close < open_price
and body >= avg_body * BIG_BODY_RATE
and lower_wick <= total_range * BOUZU_RATE
):
result.append("大陰線(安値引け)")
# ==========================
# 長い下ヒゲ(高精度ピンバー)
# ==========================
# 1. 下ヒゲがローソク足全体の 60% 以上を占める
# 2. 上ヒゲは実体以下(上値が重くない)
# 3. 実体は全体の 5%超 〜 30%以下(十字線は完全に弾く)
if (
lower_wick >= total_range * 0.60
and upper_wick <= body
and total_range * 0.05 < body <= total_range * 0.30
):
if close > open_price:
result.append("長い下ヒゲ(陽線)")
else:
result.append("長い下ヒゲ(陰線)")
return result
# ==========================
# メイン処理
# ==========================
def main():
stocks = get_nikkei225()
results = {}
print("\n日経225スキャン開始(3ヶ月平均ベース)\n")
# 一括取得(6ヶ月分取得)
df_all = yf.download(
stocks,
period="6mo",
interval="1d",
auto_adjust=False,
progress=False,
group_by="ticker",
threads=True,
)
# MultiIndexかどうか確認
multi = isinstance(df_all.columns, pd.MultiIndex)
for ticker in stocks:
code = ticker.replace(".T", "")
try:
if multi:
if ticker not in df_all.columns.get_level_values(0):
continue
df = df_all[ticker]
else:
df = df_all
# 欠損値除外
df = df.dropna(subset=["Close"])
patterns = judge_candle(df)
for p in patterns:
results.setdefault(p, []).append(code)
# 進捗を少しずつ出す
print(".", end="", flush=True)
except Exception as e:
print(f"\n{code} エラー: {e}")
# ==========================
# 結果表示
# ==========================
print("\n" + "=" * 50)
print(" スキャン結果")
print("=" * 50)
targets = [
"大陽線(高値引け)",
"大陰線(安値引け)",
"長い下ヒゲ(陽線)",
"長い下ヒゲ(陰線)",
]
for target in targets:
print(f"\n【{target}】")
if target in results:
for code in sorted(results[target]):
print(code)
else:
print("なし")
if __name__ == "__main__":
main()
こだわりのロジック解説(ここがスキャナーの命!)
ただコードを貼るだけでは面白くないので、僕がこだわった「高精度ピンバー(長い下ひげ)」の条件を解説します。
lower_wick >= total_range * 0.60下ひげが、ローソク足全体の長さ(高値から安値まで)の60%以上を占めていること。これで「しっかり押し目買いが入った形」を確定させます。upper_wick <= body上ひげは実体以下であること。いくら下ひげが長くても、上ひげも長かったら「上値が重くて売られた証拠」になってしまうので、それを排除しています。total_range * 0.05 < body <= total_range * 0.30ここが一番のポイント! 実体が小さすぎる「十字線」や「同時線」は、デイトレの順張り・逆張りとしては迷いが生じやすいので完全に弾き、しっかり方向性が出たピンバーだけを炙り出します。
4. エピローグ:10秒で終わる銘柄選定の快適さ
このプログラムを実行すると、約10秒で僕の欲しいローソク足の形状がズラリとスクリーニングできるようになりました!

実際に運用してみて分かったのですが、明確なローソク足の形だけを狙おうと判定を厳しくしすぎると、相場環境によっては「該当銘柄なし」になってしまうことも多かったです💦 このあたりは、日々の相場に合わせて数値の微調整が必要だなと感じています。
ただ、このプログラムの本当に素晴らしいところは、コードのトップに置いてある定数(BIG_BODY_RATE など)の数値を書き換えるだけで、「自分好みのローソク足の形」にいくらでもカスタマイズできる点です。
今回は僕好みの「大陽線」や「下ひげピンバー」に特化して作りましたが、「はらみ線」や「包み線(抱き線)」が欲しいという方は、ぜひロジックを追加して自分専用に改良してみてください!
以上、株道経済研究所の開発日記でした。

コメント