日本株の検証を、実測で。

1分足の歯抜けは、詰めて描くと見えなくなる|「5本後」が5分後なのは42%だけ

J-Quants の分足は、約定が無かった分のレコードを返しません。だから1分足は歯抜けになります。これを詰めて並べると、飛んでいることが見えなくなります。実測すると、隣り合う2本のうち本当に1分なのは 69.1% だけでした。

  • 1日327分すべてそろう銘柄・日は 3.22%中央値は69分
  • 隣り合う2本が本当に1分なのは 69.14%30.86% は1分ではない
  • 「5本後」がちょうど5分後なのは 42.56%。平均は 12.3分
  • 「20本後」は平均 39.1分。本来の約2倍
  • 隣り合う2本が 最大326分離れていた例もあります

公式の記述

「当APIは取引のティックデータを1分単位で集約したデータを提供しており、その1分間に取引が存在しない時間帯のデータは返却値に含まれません」

つまり歯抜けです。ここまでは仕様に書いてあります。問題はどれくらい抜けるのか、そして抜けていることに気づけるのかです。

まず、上限は327分

東証の立会時間は前場と後場に分かれ、さらに15:25〜15:29 の5分は板寄せ中で約定が成立しません。数えると1日の上限は327本です。

# 立会時間の格子を作る(327分)
grid = (list(range(9*60,   11*60+30 + 1)) +   # 09:00〜11:30  151分
        list(range(12*60+30, 15*60+24 + 1)) + # 12:30〜15:24  175分
        [15*60 + 30])                          # 15:30(大引け) 1分
assert len(grid) == 327

# 分 → 格子の位置。これで昼休みも 15:25〜15:29 も「穴」に数えずに済む
idx = {m: i for i, m in enumerate(grid)}

昼休み(11:30→12:30)を「穴」に数えてはいけません。
素直に分の差を取ると、両方の場で商いのある銘柄すべてに60分の穴が1つあることになります。実際、最初に測ったときこれを数えてしまい、「31〜60分の飛びが1.05%」と出ました。格子に直すと0.66%です。15:25〜15:29 も同じで、そもそも足が存在しません。

1日に何分そろうのか

14営業日・のべ58,761件(銘柄×日)で数えました。

約定があった分(上限327分)件数割合
327分すべてそろっている1,8903.22%
90%以上(294分超)4,9238.38%
75〜90%3,2065.46%
50〜75%6,81911.60%
10〜50%21,20036.08%
10%未満(32分以下)20,72335.27%
中央値は69分。つまり典型的な銘柄は、1日のうち69分しか約定がない

すきまなく埋まっているのは 3.22% だけです。そして3件に1件は、1日のうち32分以下しか約定していません

厚さで見るとはっきりする

売買代金約定のあった分の中央値327分そろう率半分未満の日
最も薄い7分0.0%99.9%
薄い24分0.0%99.4%
68分0.0%95.1%
厚い152分0.0%57.0%
最も厚い306分16.1%5.2%

最も厚い層でも、全部そろうのは16.1%です。「大型株なら埋まっている」とは言えません。

★ 詰めて描くと、飛びが見えなくなる

ここが本題です。歯抜けの足をそのまま左から並べると、画面上は連続した足に見えます。隣り合う2本が、立会時間で実際に何分離れているかを数えました。

# 隣り合う2本が、立会時間で何分ぶん離れているか
bars["i"] = bars["Min"].map(idx)
gap = bars["i"].diff()

print(f"本当にとなり合わせ {(gap == 1).mean() * 100:.1f}%")
# → 69.1%
隣り合う2本の実際の間隔組数割合
1分(本当にとなり)4,462,74469.143%
2分765,99111.868%
3〜5分694,63710.762%
6〜30分463,3177.178%
31〜60分42,6520.661%
1時間超25,0270.388%
645万組。最大は326分(=ほぼ丸一日の空白をまたいで隣に並んでいた)

画面で隣り合っている2本のうち、30.86% は1分ではありません。
そして8.23% は5分より離れています。チャートを見て「ここで反発した」と読んだ2本が、実際には2時間空いていることがあります。

★ 「5本後に手仕舞い」は、5分後ではない

見た目の話だけではありません。本数で数えるコードは、全部これに当たります。「5本後に手仕舞い」が実際には何分後になるか、数えました。

「5本後」(本来5分)「20本後」(本来20分)
ちょうどその分数だった42.56%30.11%
中央値6分25分
平均12.3分39.1分
本来の3倍超だった割合6.75%(30分超)3.89%(120分超)
最大326分326分
622万組・551万組で集計

「20本後」は、平均すると39.1分後でした。本来の約2倍です。移動平均の「直近20本」も同じで、20分ぶんの平均を計算しているつもりが、実際は39分ぶんになります。

薄い銘柄では、これがもっと極端になります。1日に7分しか約定しない銘柄で「直近20本」を計算すると、3営業日ぶんの平均を見ていることになります。


どうするか

  1. 足に実時刻を必ず持たせる。「i番目の足」だけで持ち回すと、この問題は最後まで見えません
  2. 本数ではなく時刻で数える。「5本後」ではなく「5分後以降の最初の足」
  3. 埋めるか空けたままかを決めて、決めたほうを結果に書く。どちらでもいいが、書いていないと後から再現できません
  4. 描くときは飛びに印を付ける。縦線でも「35分」の文字でもいい。詰めたまま何も出さないのが一番悪い
  5. 約定の少ない日は最初から外す。「立会の半分も約定が無い日は検証に使わない」と決めておく
# ★ 本数で数えない。時刻で数える
entry_i = bars["i"].iloc[k]
exit_rows = bars[bars["i"] >= entry_i + 5]     # 「5分後以降の最初の足」
if exit_rows.empty:
    skipped += 1                                # 引けまでに来なかった
else:
    ctx.close()

# 飛んでいる足を描くときは、印を付ける
if gap > 1:
    draw_gap_marker(f"{gap}分")

「5分後以降の最初の足」にすると、引けまでに来ない場合が出ます。
そのとき黙って落とすと、薄い日だけが消えて成績が良く見えます落とした件数を必ず出してください。


まとめ

1分足の歯抜けは仕様に書いてあります。それでも見落とすのは、詰めて並べると見えなくなるからです。

実測では、隣り合う2本のうち3割は1分ではなく「20本後」は平均39分後でした。どちらもコードの上では何も間違っていないのに、意味だけが静かにずれています。

本数で数えるのをやめて、時刻で数える。直し方はそれだけです。

この記事の出どころ

  • データ:J-Quants API V2 の bulk ティックから組んだ1分足。Light プラン+分足・ティックアドオン
  • 期間:2026-09-01 〜 2026-09-18 の14営業日
  • 対象:のべ58,761件(銘柄×日)。隣り合う足の組 6,454,368/「5本後」622万組/「20本後」551万組
  • 数え方:立会327分(前場151+後場176)の格子に直してから間隔を取り、昼休みと 15:25〜15:29 を穴に数えないようにした。格子の外に落ちた分は0件で、実際に15:25〜15:29 の約定は無かった
  • 環境:Windows 11 / Python 3.12 / pandas 3.0 / numpy 2.5 / pyarrow 21
  • 測定日:2026年9月21日
  • 注意:掲載したのは集計結果です。取得したデータそのものは配布していません