※本記事のコードや情報は執筆時点の仕様に基づいています。投資は自己責任であり、必ずデモ環境や少額資金でテストした上で運用してください。
株の自動売買システムの中核にあるのは、「もし株価が〇〇円以下なら買い」「もし移動平均線を上抜けたら買い」といった条件分岐のロジックです。Pythonでこの条件分岐を実現するのがif文です。
if文はPythonの最も基本的な構文の一つですが、自動売買という実践的な文脈で学ぶことで、単なる文法知識ではなく「使える技術」として身につきます。
この記事では、if文の基本構文から、比較演算子・論理演算子の使い方、そして実際の株価データを使った売買シグナル判定のコードまで、段階的に解説します。
if文の基本構文を理解する
まずはPythonにおけるif文の書き方と動作の仕組みを確認します。
if文の最もシンプルな形
Pythonのif文は以下の構文で記述します。
if 条件式:
条件がTrueのときに実行される処理
重要なポイントは以下の3つです。
- 条件式の末尾にコロン(
:)を必ず付ける - 実行する処理は半角スペース4つ分のインデントで字下げする
- インデントが揃っていないとエラーになる(Pythonはインデントが文法の一部)
if / else の構文
条件がTrueのときとFalseのときで処理を分けるには、else を使用します。
price = 2500
if price < 3000:
print("買いシグナル:株価が3,000円を下回っています")
else:
print("様子見:株価が3,000円以上です")
このコードでは、変数 price の値が3,000未満であれば買いシグナル、3,000以上であれば様子見と判定されます。
if / elif / else の構文
条件を3つ以上に分岐させるには、elif(else ifの略)を使用します。
price = 3500
if price < 2000:
print("強い買いシグナル")
elif price < 3000:
print("買いシグナル")
elif price < 4000:
print("様子見")
else:
print("売りシグナル")
elifはいくつでも追加できます。上から順番に条件が評価され、最初にTrueになった条件のブロックだけが実行されます。それ以降のelifやelseはスキップされます。
比較演算子を使いこなす
if文の条件式で使う比較演算子を整理します。売買ロジックを正確に記述するために、それぞれの意味を正しく把握してください。
比較演算子一覧
| 演算子 | 意味 | 使用例 | 売買での活用場面 |
|---|---|---|---|
== |
等しい | price == 3000 |
指値注文の判定 |
!= |
等しくない | signal != "hold" |
ホールド以外の判定 |
< |
未満 | price < 3000 |
〇〇円を下回ったら買い |
> |
超過 | price > 5000 |
〇〇円を上回ったら売り |
<= |
以下 | price <= 3000 |
〇〇円以下なら買い |
>= |
以上 | rsi >= 70 |
RSIが70以上なら売り |
「==」と「=」の違い
初心者が最も間違えやすいポイントです。
=は代入演算子(値を変数に格納する)==は比較演算子(2つの値が等しいか判定する)
# 代入(変数にvalueを格納する)
price = 3000
# 比較(priceが3000と等しいか判定する)
if price == 3000:
print("株価はちょうど3,000円です")
if文の中で
=を使うとSyntaxErrorが発生します。条件式では必ず==を使用してください。
浮動小数点数の比較に関する注意
株価データは小数点を含むことが多いため、浮動小数点数の比較には注意が必要です。
# 期待どおりに動かないケース
a = 0.1 + 0.2
if a == 0.3:
print("等しい") # これは表示されない
コンピュータの内部表現では 0.1 + 0.2 は 0.30000000000000004 となるため、== 0.3 はFalseになります。
対処法として、誤差の範囲を許容する比較を行います。
a = 0.1 + 0.2
if abs(a - 0.3) < 1e-9:
print("ほぼ等しい") # これは表示される
論理演算子で複数条件を組み合わせる
実際の売買判定では、1つの条件だけで判断することは稀です。複数の条件を組み合わせるために論理演算子を使用します。
and(かつ)
両方の条件がTrueのときだけ全体がTrueになります。
price = 2800
volume = 1500000
if price < 3000 and volume > 1000000:
print("買いシグナル:株価が安く、出来高も十分です")
or(または)
どちらか一方でもTrueであれば全体がTrueになります。
rsi = 75
macd_cross = True
if rsi > 70 or macd_cross:
print("注意シグナル:過熱感またはMACDクロスを検出")
not(否定)
条件の真偽を反転させます。
is_market_open = False
if not is_market_open:
print("市場は閉まっています。注文は翌営業日に執行されます")
複数条件の組み合わせと優先順位
and は or よりも優先して評価されます。意図しない評価順序を防ぐために、括弧(())で明示的にグループ化することを推奨します。
price = 2800
rsi = 25
volume = 500000
# 括弧なし(andが先に評価される)
if price < 3000 and rsi < 30 or volume > 1000000:
print("シグナル発生")
# 括弧あり(意図を明確にした記述)
if price < 3000 and (rsi < 30 or volume > 1000000):
print("シグナル発生")
売買ロジックでは条件の評価順序が利益に直結します。括弧を使って意図を明確にする書き方を徹底してください。
【コピペOK】株価データを使った売買シグナル判定
ここからは、実際の株価データを使って売買シグナルを判定するコードを実装します。
シンプルな価格ベースの判定
以下のコードは、yfinanceで取得した直近の終値に基づいて、シンプルな買い/売り/様子見の判定を行います。
import yfinance as yf
# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T" # トヨタ自動車
BUY_THRESHOLD = 2500 # 買いライン(円)
SELL_THRESHOLD = 3500 # 売りライン(円)
# ==============================
# データ取得と判定
# ==============================
def simple_signal():
ticker = yf.Ticker(SYMBOL)
hist = ticker.history(period="5d")
if hist.empty:
print("データを取得できませんでした。")
return
latest_close = hist["Close"].iloc[-1]
print(f"銘柄: {SYMBOL}")
print(f"直近終値: {latest_close:,.0f}円")
print("-" * 30)
if latest_close <= BUY_THRESHOLD:
print("【判定】買いシグナル")
print(f" 理由: 終値が{BUY_THRESHOLD:,}円以下")
elif latest_close >= SELL_THRESHOLD:
print("【判定】売りシグナル")
print(f" 理由: 終値が{SELL_THRESHOLD:,}円以上")
else:
print("【判定】様子見")
print(f" 理由: 終値が{BUY_THRESHOLD:,}円〜{SELL_THRESHOLD:,}円の範囲内")
if __name__ == "__main__":
simple_signal()
【コピペOK】移動平均線クロスによる売買シグナル判定
より実践的な例として、5日移動平均線と25日移動平均線のクロスを判定するコードを紹介します。
import yfinance as yf
import pandas as pd
# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T"
SHORT_WINDOW = 5 # 短期移動平均の期間
LONG_WINDOW = 25 # 長期移動平均の期間
# ==============================
# 移動平均クロス判定
# ==============================
def ma_cross_signal():
ticker = yf.Ticker(SYMBOL)
hist = ticker.history(period="3mo")
if len(hist) < LONG_WINDOW + 1:
print("データが不足しています。")
return
# 移動平均を計算
hist["MA_Short"] = hist["Close"].rolling(window=SHORT_WINDOW).mean()
hist["MA_Long"] = hist["Close"].rolling(window=LONG_WINDOW).mean()
# 直近2日分のデータを取得
today = hist.iloc[-1]
yesterday = hist.iloc[-2]
print(f"銘柄: {SYMBOL}")
print(f"直近終値: {today['Close']:,.0f}円")
print(f"短期MA({SHORT_WINDOW}日): {today['MA_Short']:,.0f}円")
print(f"長期MA({LONG_WINDOW}日): {today['MA_Long']:,.0f}円")
print("-" * 40)
# ゴールデンクロス判定
if yesterday["MA_Short"] <= yesterday["MA_Long"] and today["MA_Short"] > today["MA_Long"]:
print("【判定】ゴールデンクロス → 買いシグナル")
print(" 短期MAが長期MAを下から上に突き抜けました")
# デッドクロス判定
elif yesterday["MA_Short"] >= yesterday["MA_Long"] and today["MA_Short"] < today["MA_Long"]:
print("【判定】デッドクロス → 売りシグナル")
print(" 短期MAが長期MAを上から下に突き抜けました")
# トレンド継続の判定
elif today["MA_Short"] > today["MA_Long"]:
print("【判定】上昇トレンド継続中(様子見)")
print(" 短期MAが長期MAを上回っています")
else:
print("【判定】下降トレンド継続中(様子見)")
print(" 短期MAが長期MAを下回っています")
if __name__ == "__main__":
ma_cross_signal()
このコードのポイントは以下のとおりです。
yesterdayとtodayの2日分のデータを比較することで、クロスした瞬間を検出している<=から>への変化でゴールデンクロス、>=から<への変化でデッドクロスを判定している- 条件分岐を4パターンに分けることで、クロス発生時とトレンド継続時を区別している
if文を書くときのベストプラクティス
売買ロジックの信頼性を高めるために、if文を書く際の設計指針を押さえておいてください。
条件の順序を意識する
elif は上から順に評価されるため、より厳しい条件(限定的な条件)を上に配置する必要があります。
# 悪い例(最初の条件にすべてマッチしてしまう)
if price < 5000:
print("買い")
elif price < 3000:
print("強い買い") # ここには到達しない
# 良い例(厳しい条件を先に書く)
if price < 3000:
print("強い買い")
elif price < 5000:
print("買い")
マジックナンバーを避ける
条件式に直接数値を書き込む(マジックナンバー)と、後からロジックを変更する際に見落としが発生します。
# 悪い例
if price < 2500 and rsi < 30:
print("買い")
# 良い例(設定値を変数にまとめる)
BUY_PRICE = 2500
RSI_OVERSOLD = 30
if price < BUY_PRICE and rsi < RSI_OVERSOLD:
print("買い")
設定値をファイル冒頭に変数としてまとめておけば、銘柄や戦略を変更する際にコード全体を書き換える必要がなくなります。
早期リターンで読みやすくする
異常系の判定を先に行い、早期に関数を抜けることで、メインロジックのネスト(入れ子)を浅く保てます。
def check_signal(hist):
# 異常系を先に処理
if hist.empty:
print("データなし")
return
if len(hist) < 25:
print("データ不足")
return
# ここからメインロジック(ネストが浅い)
latest = hist["Close"].iloc[-1]
if latest < 3000:
print("買いシグナル")
よくあるエラーと対処法
「IndentationError: expected an indented block」が出る
if文の直後に処理を書く際、インデントが不足している場合に発生します。
# エラーになるコード
if price < 3000:
print("買い") # インデントがない
# 正しいコード
if price < 3000:
print("買い") # 半角スペース4つでインデント
タブとスペースの混在もこのエラーの原因になります。VS Codeの設定でインデントを「Spaces: 4」に統一してください。
「TypeError: '
数値のつもりで扱っている変数が、実際には文字列(str)型だった場合に発生します。
price = "3000" # 文字列になっている
if price < 3000: # strとintの比較でエラー
print("買い")
float() または int() で明示的に型変換してください。
price = float("3000")
if price < 3000:
print("買い")
条件が常にTrueまたは常にFalseになる
論理演算子の使い方を間違えると、条件が意図どおりに動作しません。
# 間違い(常にTrueになる)
if price < 3000 or price > 2000:
print("常にここが実行される")
# 正しい(範囲内の判定)
if price > 2000 and price < 3000:
print("2,000円〜3,000円の範囲内")
条件式が期待どおりに動いているか不安な場合は、
print()で条件式の結果(TrueまたはFalse)を出力して確認する習慣をつけてください。
まとめ
Pythonのif文は、株の自動売買における判定ロジックの基盤となる構文です。この記事で解説した内容を整理すると、以下のとおりです。
if / elif / elseで条件を分岐させ、売買シグナルを判定する- 比較演算子(
<,>,<=,>=,==,!=)で株価やテクニカル指標の閾値を評価する - 論理演算子(
and,or,not)で複数条件を組み合わせる - 括弧を使って評価順序を明示し、意図しない判定を防ぐ
- 閾値はマジックナンバーにせず、変数として冒頭にまとめる
if文の書き方を正しくマスターすれば、移動平均クロス・RSI・ボリンジャーバンドなど、あらゆるテクニカル指標を使った売買ロジックを自力で構築できるようになります。次のステップとして、for文やwhile文を使ったループ処理と組み合わせ、複数銘柄の一括スクリーニングに進んでください。

