「売上高が158億円」と分かったら、次に知りたくなるのは「前の期より増えたのか」です。ただ、前期比はいつでも出せる数字ではありません。前の期の値がない、決算期の長さが違う、前の期が赤字だった、といった場合には、計算はできても意味のある比較になりません。
今回は、実践⑤まで読んできた企業分析画面で、決算期を選ぶ処理と、前期比を出す条件・出さない条件を読みます。後半では、2社を同じ決算期で並べる「企業比較」の条件も確かめます。
画面の企業と数値は架空のサンプルです。 実企業のデータへの切り替えは実践⑧で扱います。
私たち株式会社Crabgrassは、企業の財務データなどをAPIで提供するZENITH Codeを開発しています。本記事は自社サービスのデータを使うためのテンプレートを題材にした実装例です。
この記事のコードは、公開サンプル集のcompany-analysisテンプレート(執筆時点の版)に対応しています。起動方法は実践④の「ローカルで開く準備」と同じです。
1. 今回扱う画面と操作
| 操作 | 画面で変わるもの | 今回読むコード |
|---|---|---|
| 「対象決算期」で別の期を選ぶ | 数値カード、期のバッジ、表と出典の印 |
reviewPeriod の change イベントと render()
|
| 数値カードの下の前期比を見る | 「+17.9% 前期比」または「前期比較なし」 |
model.mjs の changeRate()
|
| 「企業比較」で共通の決算期を選ぶ | 2社の棒と、比較条件の一致・不一致 |
renderComparison() と comparisonConditions()
|
2. 決算期を選ぶ
対象決算期のプルダウンは、データを読み込むたびに作り直しています。
if (!current.years.some(r => r.fiscalPeriod === selectedPeriod)) selectedPeriod = current.years.at(-1)?.fiscalPeriod ?? "";
$("reviewPeriod").replaceChildren(...[...current.years].reverse().map(r => node("option", `${r.fiscalPeriod} FY`, {value:r.fiscalPeriod})));
$("reviewPeriod").value = selectedPeriod;
1行目は、選んでいた期が今のデータにない場合に、一番新しい期を選び直す処理です。current.years は実践④で読んだ normalize() が古い順に並べているので、at(-1) が最新の期になります。別の企業に切り替えたときに、前の企業で選んでいた期が残って空の画面になることを防ぎます。
2行目では、配列を reverse() で新しい順にしてから選択肢を作っています。プルダウンの一番上に最新の期が来るようにするためです。元の current.years は書き換えず、[...current.years] で複製してから並べ替えています。reverse() は配列そのものを並べ替えるので、複製しないとグラフや表の期の順まで逆になってしまいます。
期を選び直したときの処理は1行です。
$("reviewPeriod").addEventListener("change",()=>{selectedPeriod=$("reviewPeriod").value;render();});
選んだ期を selectedPeriod に入れて、render() で画面全体を描き直します。render() の中では、数値カードの期を次のように決めています。
latest = years.find(r => r.fiscalPeriod === selectedPeriod) ?? years.at(-1)
名前は latest ですが、中身は「選んでいる期」です。数値カード、期のバッジ、表の列の色、出典の「•」は、どれもこの selectedPeriod を見ています。1つの値から全部を決めるので、カードは2025-03期なのに表の印は2026-03期、というずれが起きません。
グラフだけは、期を選んでも3期すべてを表示したままです。推移を見る場所なので、1期だけに絞ると比べる相手がなくなるためです。
3. 前期比を出す条件
数値カードの下の前期比は、model.mjs の changeRate() が計算します。
export function changeRate(current, previous, field) {
if (!current || !previous || current.period !== "FY" || previous.period !== "FY" ||
!current.accountingStandard || current.accountingStandard !== previous.accountingStandard ||
current.fiscalPeriod.slice(5) !== previous.fiscalPeriod.slice(5) ||
Number(current.fiscalPeriod.slice(0,4)) - Number(previous.fiscalPeriod.slice(0,4)) !== 1 ||
!Number.isFinite(current.fiscalPeriodDays) || !Number.isFinite(previous.fiscalPeriodDays) ||
current.fiscalPeriodDays < 360 || current.fiscalPeriodDays > 366 ||
previous.fiscalPeriodDays < 360 || previous.fiscalPeriodDays > 366) return null;
const a = finite(current[field]), b = finite(previous[field]);
if (a === null || b === null) return null;
if (field === "operatingMargin") return a-b;
return b > 0 ? (a-b)/b : null;
}
条件が長く見えますが、確かめていることは次の表のとおりです。1つでも満たさなければ null を返し、画面には「前期比較なし」と表示します。
| 確かめること | コード | 満たさない例 |
|---|---|---|
| 前の期がある | !previous |
一番古い2024-03期を選んだ |
| どちらも通期 | period !== "FY" |
四半期の値が混ざった |
| 会計基準が同じ | accountingStandard |
日本基準からIFRSへ変えた年 |
| 決算月が同じ | fiscalPeriod.slice(5) |
3月決算から12月決算へ変えた |
| ちょうど1年前 | 年の差が1 | 間の期のデータが欠けている |
| どちらも約1年 | 360〜366日 | 決算期の変更で9か月の期がある |
| どちらの値もある | finite() |
前の期の営業利益が未取得 |
| 前の期が正の値 | b > 0 |
前の期が営業赤字 |
最後の「前の期が正の値」は、金額の増減率だけの条件です。前期が−4.2億円で今期が+6.1億円のとき、式どおりに計算すると「−245%」になります。業績は良くなっているのに、符号だけを見ると悪化したように読めてしまいます。こうした場合は、率を出さずに金額そのものを見たほうが誤解がありません。
営業利益率は a-b で、率の差を返します。12.5%と10.6%なら+1.9ポイントです。率同士の「増減率」(10.6%から12.5%は+18%)とは別の数字なので、画面では pt と書いて区別しています。
`${rate > 0 ? "+" : ""}${field === "operatingMargin" ? (rate*100).toFixed(1) + " pt" : percent(rate,lang)} ${t("yearChange")}`
rate > 0 のときだけ + を付けています。マイナスの数値は percent() が自分で - を付けるためです。
4. 「前期比較なし」になる例
架空クラウドに切り替えると、前期比が出るカードと出ないカードが並びます。
| カード | 2026-03期 | 2025-03期 | 結果 |
|---|---|---|---|
| 売上高 | 76億円 | 58億円 | +31% |
| 営業利益 | 6.1億円 | 未取得(null) |
前期比較なし |
| 営業利益率 | 8% | 未取得(null) |
前期比較なし |
架空クラウドの2025-03期の営業利益は、実践④で見た欠損の例です。前の期の値がないので、営業利益の前期比は出せません。営業利益率もAPIの値が null なので同じです。
対象決算期で2025-03期を選び直しても、営業利益は「前期比較なし」のままです。今度は今期の値が欠損で、前の2024-03期は営業赤字です。どちらの理由でも、0円とみなして計算することはしません。
5. 2社を同じ決算期で比べる
「企業比較」では、選んでいる企業と別の企業を、同じ決算期で並べます。
共通の決算期のプルダウンには、2社の両方にある期だけを並べます。
const common = other ? current.years.filter(a=>other.years.some(b=>b.fiscalPeriod===a.fiscalPeriod)) : [];
3月決算の会社と12月決算の会社を比べると、fiscalPeriod が一致する期がないので、共通の決算期は空になります。画面には「共通の決算期がありません。」と表示し、棒は描きません。決算月が違う会社同士では、同じ「2026年の通期」でも対象の月が9か月ずれているためです。
期が選べたら、comparisonConditions() で比べる条件をもう一度確かめます。
export function comparisonConditions(a, b) {
return Boolean(a && b && a.period === "FY" && b.period === "FY" &&
a.fiscalPeriod === b.fiscalPeriod && a.accountingStandard &&
a.accountingStandard === b.accountingStandard &&
Number.isFinite(a.fiscalPeriodDays) && a.fiscalPeriodDays > 0 &&
a.fiscalPeriodDays === b.fiscalPeriodDays);
}
条件を満たすと「✓ 決算期・会計基準・期間日数が一致」、満たさないと「! 比較条件に差異・不明点あり」と表示します。条件が違っても棒は描きます。日本基準の会社とIFRSの会社を並べたいこともあるためです。そのかわり、会計基準と期間日数をそのまま表示して、違いがあることを読む人に伝えます。
model.mjs の関数の上には、次のコメントがあります。
// Matching metadata is a necessary check, not evidence of economic comparability.
決算期や会計基準がそろっていることは、比べるための最低限の確認です。業種や事業の構成が違えば、同じ営業利益率でも意味は変わります。画面の下にも「業種や事業構成の違いを調整した比較ではありません」と書いています。会社同士の比べ方は実践③でも扱いました。
6. 小さな変更で処理を確かめる
前期比に、増減の金額も並べてみます。「+17.9%」だけでは、どれくらいの金額が増えたのかが分かりにくいためです。
app.mjs の render() で、前期比の文字を作る1行を、次の3行に置き換えます。
const diff = rate === null || field === "operatingMargin" ? null : latest[field] - previous[field];
const amount = diff === null ? "" : `${diff > 0 ? "+" : ""}${money(diff, lang, true)}${t("hundredMillion")} / `;
const change = node("div", rate === null ? t("notComparable") : `${amount}${rate > 0 ? "+" : ""}${field === "operatingMargin" ? (rate*100).toFixed(1) + " pt" : percent(rate,lang)} ${t("yearChange")}`, {class:"kpi-change"});
rate が null でないときだけ金額を計算しています。changeRate() の条件を通った組だけが対象になるので、決算期の長さが違う期や、欠損の期の差を出してしまうことはありません。営業利益率は金額ではないので対象外にしています。
保存してブラウザを再読み込みすると、架空精密工業の2026-03期は次のように表示されます。
| カード | 変更前 | 変更後 |
|---|---|---|
| 売上高 | +17.9% 前期比 | +24億円 / +17.9% 前期比 |
| 営業利益 | +39.4% 前期比 | +5.6億円 / +39.4% 前期比 |
| 営業利益率 | +1.9 pt 前期比 | +1.9 pt 前期比 |
架空クラウドの2026-03期では、売上高は「+18億円 / +31% 前期比」になり、営業利益は「前期比較なし」のままです。
この変更でも、条件の判断は changeRate() に任せています。表示の側で別の条件を書き足すと、率は出ないのに金額だけ出る、といった食い違いが起きやすくなります。
7. 確認箇所
| 症状 | 確認箇所 |
|---|---|
| 期を選んでも数値カードが変わらない |
selectedPeriod に値が入っているか。render() を呼んでいるか |
| グラフや表の期の順が逆になった |
reverse() の前に配列を複製しているか |
| 前期比がいつも「前期比較なし」 | 期の差が1年か。fiscalPeriodDays が入っているか |
| 赤字から黒字の期で前期比が出ない | 前の期が0以下のときは率を出さない仕様 |
| 共通の決算期が選べない | 2社の決算月が同じか |
| 比較の欄に「!」が出る | 会計基準または期間日数が違う。表示された値を確認 |
コードをAIと一緒に変更する場合は、比べてよいかの判断をどこで行うかを指定すると、条件の二重管理を避けられます。
company-analysisテンプレートの数値カードで、前期比の前に増減額を表示してください。
対象は app.mjs の render() にある、前期比の文字を作る部分です。
model.mjs の changeRate() が null を返すときは、増減額も表示しないでください。
増減額は億円で表示し、プラスのときは + を付けます。営業利益率は対象外です。
changeRate() の条件や、null を 0 に置き換える処理は追加しないでください。
変更箇所と、架空精密工業・架空クラウドで確認する操作を説明してください。
8. 次回は見た目と操作
今回は、決算期を1つの値で管理し、前期比と企業比較に「出さない条件」があることを確かめました。次回のZENITH Code実践⑦では、テーマ、余白、文字の大きさ、スマホでの並び方、表示設定の保存など、画面の見た目と操作を整える部分を読みます。



