CH.01 · 財金程式設計互動教材

金融網站與程式設計的完整地圖

從一張白紙開始,理解 HTML、CSS、JavaScript、JSON、Python 五種技術如何分工,並親手完成第一個能實際運算的複利終值計算器。

FV = PV(1+r)ⁿ

本章學習目標

  • 分辨 HTML/CSS/JS/JSON/Python 的分工角色
  • 理解「輸入 → 驗算 → 運算 → 顯示」的系統流程
  • 親手建立並修改一個可運作的複利計算器
  • 學會判讀 JavaScript 常見錯誤訊息並修正

01金融網站的四個層次

一個完整的金融網站,從使用者看到的畫面到後台管理,可以拆成四層。初學者不需要第一天就精通全部,先從前台介面與簡單運算開始就好。

前台介面層首頁、導覽列、輸入欄位、按鈕、表格與圖表——使用者直接看到、操作的部分。
資料層保存文章、書籍、考題、金融商品與工具設定,常見格式為 JSON、CSV、Markdown。
運算層執行複利、債券定價、報酬率、標準差、Black-Scholes 模型與 VaR 等金融公式。
管理後台層新增文章、修改資料、上傳圖片、管理題庫、控制內容上下架。

02五種技術的分工

複利計算器背後其實動用了五種技術,各自只負責自己最擅長的事——這正是網頁開發「分工」的核心概念。

技術主要職責金融應用舉例
HTML網頁結構與內容放置本金、利率、年數輸入欄位
CSS排版與視覺設計讓輸入畫面清楚美觀、支援手機版
JavaScript互動邏輯與即時計算讀取數值並執行複利公式
JSON結構化資料儲存與傳遞保存文章、題庫、金融商品資料
Python大量分析與後台管理分析股票資料、建立 Streamlit 後台

Python 是一種容易閱讀、應用範圍廣泛的程式語言,適合執行較複雜的工作:清理股票價格資料、計算大量報酬率、估算債券殖利率、進行風險分析、執行投資組合模擬、建立 Streamlit 管理後台、自動產生 JSON 資料、進行檔案備份。本書將 JavaScript 與 Python 依工作需求分工:簡單即時的網頁計算由 JavaScript 完成;較大量的資料處理與管理工作則交由 Python 執行。

03第一個金融網站專案:建立專案資料夾

在電腦中建立資料夾 financial-platform,並在其中建立以下結構:

financial-platform/
├─ index.html      ← 首頁與複利工具
├─ css/
│  └─ style.css    ← 網頁外觀與排版
├─ js/
│  └─ calculator.js ← 金融計算與互動
├─ data/           ← 未來存放 JSON / CSV
├─ images/         ← 圖片及圖示
└─ README.md       ← 專案說明
檔案或資料夾主要用途
index.html網站首頁與複利工具結構
css/style.css網頁外觀與排版
js/calculator.js金融計算與互動邏輯
data/未來存放 JSON 或 CSV 資料
images/存放圖片及圖示
README.md記錄專案說明與操作方式

Windows 建立方式

  1. 在桌面或指定位置按滑鼠右鍵,選擇「新增」→「資料夾」,命名為 financial-platform。
  2. 進入資料夾後建立 css、js、data 及 images 四個子資料夾。
  3. 使用 Visual Studio Code 建立 index.html、css/style.css 及 js/calculator.js。
  4. 在主資料夾建立 README.md。
  5. 注意副檔名:檔案應為 index.html,不是 index.html.txt。

使用 Visual Studio Code 開啟專案
開啟 Visual Studio Code →「檔案」→「開啟資料夾」→ 找到 financial-platform →「選取資料夾」。左側檔案總管應顯示完整資料夾結構。

!

不建議使用 Word 編輯程式碼,因為 Word 可能加入特殊格式而導致程式錯誤。

04複利終值的金融觀念

單利與複利——單利只針對最初本金計算利息。假設本金 100,000 元,年利率 5%,投資 3 年:

單利終值 = 100,000 + 100,000 × 5% × 3 = 115,000 元

複利則將前一期利息加入本金,下一期再以較大的金額計息:

複利終值 = 100,000 × (1.05)³ = 115,762.50 元

兩者的差距在投資期間短時可能不明顯,但投資期間越長,複利效果越顯著。

複利終值公式

FV = PV × (1 + r)ⁿ

FV 為未來價值;PV 為目前本金;r 為每期報酬率;n 為總期數。

假設本金 200,000 元,年報酬率 6%,投資 15 年:FV = 200,000 × (1.06)¹⁵ ≈ 479,312 元。

百分比轉換——使用者通常輸入 5,代表 5%。但程式執行運算時,必須將 5% 轉成 0.05:

const annualRate = ratePercent / 100; // 5 → 0.05

// 正確:100,000 × (1 + 0.05)^10
// 錯誤:100,000 × (1 + 5)^10  ← 忘記除以 100
!

金融程式最常見的錯誤:忘記把百分比除以 100。使用者輸入「5」代表 5%,但程式運算時必須是 0.05。若直接把 5 代入公式,等於用 500% 計算,結果會誇張地離譜。永遠記得:const annualRate = ratePercent / 100;

模型的限制——複利計算器只是情境模擬,不代表實際投資一定會依照固定報酬率成長。實際投資可能受到下列因素影響:

i

網站應將計算結果稱為「試算結果」或「情境估計」,而不是「保證報酬」。

05系統設計流程(IPO 架構)

幾乎所有金融工具都遵循同一種資料流動方式:輸入 → 驗證 → 運算 → 輸出。記住這個順序,之後學債券定價、選擇權、退休試算都是同一套邏輯。本工具需要三項輸入(本金、年報酬率、投資年數),系統輸出投資期末金額、投資總獲利及情境說明。

① 使用者輸入本金 / 年報酬率 / 投資年數
② 資料驗證空白、負數、不合理數值檢查
③ 執行公式FV = PV × (1 + r)ⁿ
④ 顯示結果終值 / 總獲利 / 情境說明

06HTML 網頁結構實作

HTML 負責建立標題、說明文字、輸入欄位、計算按鈕及結果區。

程式區塊 1index.html(完整版)
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>複利終值計算器</title>
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
<main class="page-container">
  <section class="calculator-card">
    <h1>複利終值計算器</h1>
    <p class="intro-text">
      輸入本金、預期年報酬率及投資年數,試算投資期末金額。
    </p>
    <div class="form-group">
      <label for="principal">投資本金(元)</label>
      <input type="number" id="principal" min="0" step="1000"
             placeholder="例如:100000">
    </div>
    <div class="form-group">
      <label for="rate">預期年報酬率(%)</label>
      <input type="number" id="rate" step="0.1" placeholder="例如:5">
    </div>
    <div class="form-group">
      <label for="years">投資年數</label>
      <input type="number" id="years" min="1" step="1" placeholder="例如:10">
    </div>
    <button type="button" id="calculateButton">開始計算</button>
    <div id="message" class="message" aria-live="polite"></div>
    <section id="resultBox" class="result-box hidden">
      <h2>試算結果</h2>
      <p>投資期末金額:<strong id="futureValue"></strong></p>
      <p>投資總獲利:<strong id="totalProfit"></strong></p>
      <p id="resultDescription"></p>
    </section>
    <p class="notice">本工具僅供金融教育及情境試算使用,不代表投資報酬保證。</p>
  </section>
</main>
<script src="js/calculator.js"></script>
</body>
</html>

HTML 重點說明

標籤 / 屬性用途說明
<!DOCTYPE html>宣告使用 HTML5 標準
lang="zh-Hant"設定頁面主要語言為繁體中文
meta charset="UTF-8"使瀏覽器正確顯示中文字元
viewport meta讓網頁在手機依裝置寬度顯示
<label for="...">說明輸入欄位內容,連結對應 input
input type="number"限制欄位輸入數值
id="..."程式辨識網頁元素的唯一名稱
aria-live="polite"讓輔助工具注意動態更新的訊息
i

id 不可重複。本頁使用的 id 清單:principal、rate、years、calculateButton、message、resultBox、futureValue、totalProfit、resultDescription。同一頁面中,每個 id 原則上只能出現一次,JavaScript 根據 id 找到指定欄位。

07CSS 畫面設計實作

程式區塊 2css/style.css(完整版)
* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: "Microsoft JhengHei", Arial, sans-serif;
  background: #f4f6f8;
  color: #1f2933;
}

.page-container {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 24px;
}

.calculator-card {
  width: 100%;
  max-width: 560px;
  background: #ffffff;
  padding: 32px;
  border-radius: 16px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.08);
}

h1 { margin-top: 0; margin-bottom: 12px; font-size: 30px; }
.intro-text { margin-bottom: 24px; line-height: 1.7; color: #52606d; }
.form-group { margin-bottom: 18px; }
label { display: block; margin-bottom: 8px; font-weight: 700; }

input {
  width: 100%; padding: 12px 14px;
  border: 1px solid #bcccdc;
  border-radius: 8px; font-size: 16px;
}
input:focus { outline: 2px solid #4c8bf5; border-color: #4c8bf5; }

button {
  width: 100%; margin-top: 8px; padding: 14px;
  border: none; border-radius: 8px;
  background: #2457a6; color: #ffffff;
  font-size: 17px; font-weight: 700; cursor: pointer;
}
button:hover { background: #183f7a; }

.message { min-height: 24px; margin-top: 16px; font-weight: 700; }
.error-message { color: #b42318; }

.result-box {
  margin-top: 20px; padding: 20px;
  border-radius: 10px; background: #edf5ff;
}
.result-box h2 { margin-top: 0; }
.result-box strong { font-size: 20px; }

.notice { margin-top: 20px; font-size: 14px; color: #66788a; }
.hidden { display: none; }

@media (max-width: 600px) {
  .calculator-card { padding: 22px; }
  h1 { font-size: 25px; }
}

CSS 重點說明

CSS 屬性用途說明
box-sizing: border-box寬度計算包含內距與邊框,較易控制版面
max-width: 560px限制卡片最大寬度,避免在大螢幕上過度延伸
border-radius產生圓角效果
box-shadow產生卡片陰影,增加立體感
:focus 偽類使用者點選輸入欄位時顯示藍色提示框
:hover 偽類滑鼠移到按鈕上時改變背景色
.hidden { display:none }暫時隱藏結果區,計算完成後顯示
@media (max-width:600px)響應式設計,手機版使用較小的內距與字體

08JavaScript 金融計算實作

程式區塊 3js/calculator.js(完整版)
"use strict";

// -- 取得網頁元素 --
const principalInput = document.getElementById("principal");
const rateInput = document.getElementById("rate");
const yearsInput = document.getElementById("years");
const calculateButton = document.getElementById("calculateButton");
const messageBox = document.getElementById("message");
const resultBox = document.getElementById("resultBox");
const futureValueText = document.getElementById("futureValue");
const totalProfitText = document.getElementById("totalProfit");
const resultDescription = document.getElementById("resultDescription");

// -- 金融計算函數 --
function calculateFutureValue(principal, annualRate, years) {
  return principal * Math.pow(1 + annualRate, years);
}

// -- 格式化新臺幣 --
function formatCurrency(amount) {
  return new Intl.NumberFormat("zh-TW", {
    style: "currency",
    currency: "TWD",
    maximumFractionDigits: 0
  }).format(amount);
}

// -- 顯示錯誤訊息 --
function showError(message) {
  messageBox.textContent = message;
  messageBox.className = "message error-message";
  resultBox.classList.add("hidden");
}

function clearMessage() {
  messageBox.textContent = "";
  messageBox.className = "message";
}

// -- 輸入驗證 --
function validateInputs(principal, ratePercent, years) {
  if (Number.isNaN(principal) || Number.isNaN(ratePercent) || Number.isNaN(years))
    return "請完整輸入本金、報酬率及年數。";
  if (principal <= 0) return "投資本金必須大於 0。";
  if (years <= 0) return "投資年數必須大於 0。";
  if (!Number.isInteger(years)) return "本工具的投資年數請輸入整數。";
  if (ratePercent <= -100) return "年報酬率不得小於或等於 -100%。";
  if (ratePercent > 100) return "年報酬率過高,請確認輸入是否正確。";
  return "";
}

// -- 主計算流程 --
function handleCalculation() {
  const principal = Number(principalInput.value);
  const ratePercent = Number(rateInput.value);
  const years = Number(yearsInput.value);

  const errorMessage = validateInputs(principal, ratePercent, years);
  if (errorMessage !== "") { showError(errorMessage); return; }

  clearMessage();
  const annualRate = ratePercent / 100;
  const futureValue = calculateFutureValue(principal, annualRate, years);
  const totalProfit = futureValue - principal;

  futureValueText.textContent = formatCurrency(futureValue);
  totalProfitText.textContent = formatCurrency(totalProfit);
  resultDescription.textContent =
    `以年報酬率 ${ratePercent}% 投資 ${years} 年,` +
    `本金約成長為原來的 ${(futureValue / principal).toFixed(2)} 倍。`;
  resultBox.classList.remove("hidden");
}

// -- 事件監聽 --
calculateButton.addEventListener("click", handleCalculation);

09JavaScript 程式逐步解析

步驟程式寫法說明
取得欄位document.getElementById("principal")透過 id 找到 HTML 輸入欄位
轉換數值Number(principalInput.value)將文字欄位值轉成可運算數字
輸入驗證validateInputs()檢查空白、負數、不合理值
百分比轉換ratePercent / 1005 → 0.05,避免計算錯誤
計算終值Math.pow(1 + annualRate, years)執行複利公式 (1+r)^n
格式化金額Intl.NumberFormat("zh-TW",{...}).format()顯示新臺幣千分位格式
顯示結果resultBox.classList.remove("hidden")移除 hidden class 呈現結果
事件監聽addEventListener("click", handleCalculation)點擊按鈕時執行計算函數

網頁互動的基本模式:使用者動作 → 事件發生 → 執行函數 → 更新畫面。

10操作實務與測試

開啟網頁——儲存三個檔案(index.html、style.css、calculator.js)後,回到 financial-platform 資料夾,使用瀏覽器開啟 index.html。

基本測試——輸入本金 100,000 元、年報酬率 5%、投資年數 10 年,預期結果:

項目預期結果
投資期末金額約 162,889 元
投資總獲利約 62,889 元
成長倍數約 1.63 倍

邊界測試——金融工具不能只測試正常資料,也要測試錯誤資料:

測試情境輸入內容預期反應
空白欄位未輸入本金顯示請完整輸入
零本金本金輸入 0顯示本金必須大於 0
負年數年數輸入 -5顯示年數必須大於 0
小數年數年數輸入 3.5顯示年數應為整數
報酬率 -100%利率輸入 -100顯示報酬率不合理
過高報酬率利率輸入 500提醒確認資料
零報酬率利率輸入 0終值應等於本金

結果合理性檢查

11實務案例

(一)長期複利效果

王先生目前投入 200,000 元,預期年報酬率 6%,分別投資 10 年、20 年與 30 年:

投資期間預估終值每多 10 年增加金額
10 年358,170 元
20 年641,427 元約 283,257 元
30 年1,148,698 元約 507,271 元

後面 10 年的增加金額更大,原因是較大的本金持續參與複利。這就是「時間是複利最好的朋友」的核心原理。

(二)高報酬率假設的風險

某網站讓使用者以每年 30% 的報酬率試算 30 年,投入 100,000 元,計算結果會超過 2.62 億元。數學公式可能沒有錯,但金融假設極為樂觀。長期維持 30% 年報酬率十分困難,工具應明確提醒:高報酬通常伴隨高風險、歷史報酬不代表未來報酬、固定年報酬率只是簡化假設、長期試算對利率假設非常敏感。

(三)百分比轉換錯誤案例

學生在程式中直接寫 const annualRate = ratePercent;,未除以 100。使用者輸入 5 時,程式將其當成 500%,產生極端結果。

// ✗ 錯誤:忘記除以 100
const annualRate = ratePercent; // 5 被當成 500%

// ✓ 正確:轉換百分比
const annualRate = ratePercent / 100; // 5 → 0.05

12常見錯誤與除錯對照表

在挑戰任務中,你會實際遇到這些狀況——先熟悉症狀與原因,除錯時會更有方向感。

症狀可能原因修正方式
網頁只有文字沒有樣式CSS 路徑錯誤或未儲存確認 <link href="css/style.css">
按鈕沒有反應JS 路徑錯誤或 id 名稱不一致確認 <script src="js/calculator.js">
中文字顯示亂碼缺少或錯誤的 charset 設定加入 <meta charset="UTF-8">
輸入 5% 卻得到極大結果忘記將百分比除以 100const annualRate = ratePercent / 100
顯示 NaN欄位空白或輸入非數字加入 Number.isNaN() 輸入驗證
修改後畫面未更新檔案未儲存或瀏覽器快取儲存後按 Ctrl+F5 強制重新整理

13關鍵字

金融網站前台後台 資料層運算層HTML CSSJavaScriptJSON Python輸入驗證複利終值 現在價值年報酬率百分比轉換 響應式網頁DOM事件監聽 情境試算除錯

14實作練習

(一)基礎操作
  • 將預設測試資料改為本金 300,000 元、年報酬率 4%、投資 12 年,記錄計算結果
  • 將按鈕文字由「開始計算」改為「立即試算」
  • 將頁面標題改為「個人投資複利試算工具」
  • 在結果區增加「原始本金」顯示
  • 測試報酬率為 0% 時,終值是否等於本金
(二)功能修改
  • 增加「清除資料」按鈕,點擊後清空所有欄位與結果
  • 增加「累積報酬率」顯示:(終值 - 本金) / 本金 × 100%
  • 增加本金不得高於 10 億元的檢查
  • 增加投資年數不得超過 100 年的檢查
  • 報酬率高於 20% 時,顯示高風險提醒文字
(三)進階挑戰
  • 增加每年期末資產金額逐年表格
  • 加入 Chart.js 繪製資產成長曲線圖
  • 增加單利與複利比較,並繪製差距圖
  • 增加每月複利功能(將年利率轉換為月利率)
  • 加入「樂觀(8%)、中性(5%)、保守(3%)」三種報酬率情境比較
  • 將工具整合進個人金融知識網站的導覽系統

上面「基礎操作」的前兩項與「功能修改」的第一項,正是本章挑戰任務(04 分頁)裡任務一、二、三的原型——先在這裡讀懂需求,再到挑戰任務分頁動手實作與除錯。

本章結語——本章建立了金融程式設計與網站實作的基本地圖。金融網站不只是將文字放到網路上,而是將金融知識轉化為可以輸入、計算、比較及解釋的互動工具。

HTML 負責網頁骨架,CSS 負責畫面設計,JavaScript 負責互動與金融計算,JSON 負責結構化資料,Python 則適合大量分析與後台管理。這些技術各有分工,並不需要在一開始全部精通。

讀者已完成第一個複利終值計算器,並理解輸入—處理—輸出的基本架構。這個架構未來可以延伸至債券定價、股票報酬、選擇權、退休規劃與風險管理。

下一章將進一步說明 HTML、CSS 與 JavaScript 的互動設計,並將目前的單一複利工具擴充為包含現值、終值、報酬率與投資年數反推的多功能貨幣時間價值計算器。

複利終值計算器(教材原始範例)

這就是本章要完成的成品,直接輸入本金、預期年報酬率、投資年數試試看。它與課本第六~八節的 index.html/style.css/calculator.js 完全對應——等一下的挑戰任務就是在這份程式碼上動手修改。

  index.html — 在瀏覽器中執行

觀念測驗

共 15 題選擇題,涵蓋本章所有核心觀念。每題作答後會立即顯示解析。

0 / 15 已作答

挑戰任務:修改程式碼,讓工具自己告訴你哪裡錯

下面兩個練習都是「真的會執行」的程式碼。修改完成後按下「執行測試」,系統會把你的程式碼放進真實瀏覽器環境中運行,並用白話文告訴你哪一行邏輯不對、哪個語法漏了什麼——就像有一位助教在旁邊即時看你的程式碼。

任務一:功能修改

對應教材「十四、實作練習(一)基礎操作」

難度:入門
  • 把按鈕文字從「開始計算」改成「立即試算」
  • 在結果區補上「原始本金」這一行的顯示邏輯(HTML 已經幫你留好 #originalPrincipal 欄位,只需要在 JavaScript 中賦值)
js/calculator.js — 可直接編輯
提示(卡住了再打開)
按鈕文字:可以在 JS 裡用 calculateButton.textContent = "..."; 動態修改。

補充欄位:在 handleCalculation() 函式中,計算完 futureValue 之後,加入一行把對應內容寫進指定的 id。
💡 查看範例解答(建議自己先試過再打開)


            

看完解答後,可以按上面的「還原初始程式碼」重新自己動手做一次,或按「換一題再練習」挑戰另一個類似的任務。

任務二:抓出隱藏的語法錯誤

對應教材「十二、常見錯誤與除錯」— id 對不起來

難度:除錯
  • 這份程式碼交接自另一位同學,執行後按鈕完全沒反應
  • 找出問題並修正,讓計算器恢復正常運作
js/calculator.js — 藏有 1 個 bug
提示(卡住了再打開)
瀏覽器主控台(開發人員工具的 Console)如果出現「Cannot read properties of null」,代表 document.getElementById("...") 抓到的是 null。逐一比對 HTML 裡每個 id="..." 跟 JS 裡 getElementById("...") 的拼字是否一模一樣。
💡 查看範例解答(建議自己先試過再打開)


            

看完解答後,可以按「還原初始程式碼」重新自己抓一次,或按「換一題再練習」練習抓另一個類似的 id 錯誤。

任務三:抓出百分比換算錯誤

對應教材「十一、實務案例(三)百分比轉換錯誤案例」

難度:除錯
  • 這份程式碼可以正常執行、不會報錯,但算出來的數字完全不合理
  • 本金 100,000、報酬率 5%、投資 10 年,正確答案應約為 162,889 元
  • 找出問題所在並修正
js/calculator.js — 數字不合理,但沒有紅字錯誤
提示(卡住了再打開)
這是「跑得動、但答案錯」的類型,找不到紅字錯誤時,回頭檢查每一個數學運算式,尤其是使用者輸入的「5」到底有沒有被換算成「0.05」。
💡 查看範例解答(建議自己先試過再打開)


            

看完解答後,可以按「還原初始程式碼」重新自己抓一次,或按「換一題再練習」練習抓另一種百分比換算錯誤。