📊 リアルタイム株価アラートシステム
設定した条件で株価を24時間監視、即座に通知
本格的な株価アラートシステムの実装ガイド
リアルタイム監視と自動通知を実現する完全ガイド
株価データソースの選定
リアルタイム株価取得のためのAPI選び
- Alpha Vantage: 無料枠あり、1分足から日足まで対応。リアルタイムデータは1分ごとに更新
- Yahoo Finance API (yfinance): Pythonライブラリで簡単に利用可能、無料だが非公式
- Polygon.io: 月$199〜、ミリ秒単位のリアルタイムデータ、米国株特化
- 楽天証券 MarketSpeed API: 日本株に強い、口座開設が必要
- Finnhub: 無料枠60リクエスト/分、ニュースやSNS感情分析も取得可能
- Kabu+ API: auカブコム証券のAPI、日本株のリアルタイム情報
💡 推奨: 個人開発ならAlpha Vantage無料枠でスタート(1日500リクエスト)。本格運用なら楽天証券やauカブコム証券のAPIで日本株に特化するのが現実的です。
システムアーキテクチャ設計
24時間稼働する監視システム
- フロントエンド: React + Next.js でアラート設定UIを構築
- バックエンド: Node.js + Express または Python + FastAPI
- データベース: PostgreSQL でユーザー・アラート設定を保存
- 監視システム: cron / 定期ジョブで1分〜5分ごとに株価をチェック
- キャッシュ: Redis で株価データをキャッシュし、API呼び出しを削減
- 通知サービス: SendGrid(メール)、LINE Messaging API、FCM(プッシュ通知)
- WebSocket: リアルタイムで株価更新をクライアントに配信
株価取得システムの実装
Alpha Vantage APIで株価を取得
- リアルタイムクォート: TIME_SERIES_INTRADAYで1分足データ取得
- 日次データ: TIME_SERIES_DAILYで過去の終値・始値など
- レート制限: 無料枠は1分5リクエスト、1日500リクエスト
- キャッシング戦略: 同じ銘柄は1分間キャッシュしてAPI呼び出しを節約
const axios = require('axios');
const redis = require('redis');
const client = redis.createClient();
const API_KEY = process.env.ALPHA_VANTAGE_KEY;
async function getStockPrice(symbol) {
// Redisキャッシュをチェック
const cached = await client.get(`stock:${symbol}`);
if (cached) {
return JSON.parse(cached);
}
// APIから取得
const url = `https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${symbol}&apikey=${API_KEY}`;
const response = await axios.get(url);
const data = response.data['Global Quote'];
const stockData = {
symbol: data['01. symbol'],
price: parseFloat(data['05. price']),
change: parseFloat(data['09. change']),
changePercent: parseFloat(data['10. change percent'].replace('%', '')),
volume: parseInt(data['06. volume']),
timestamp: new Date()
};
// 1分間キャッシュ
await client.setEx(`stock:${symbol}`, 60, JSON.stringify(stockData));
return stockData;
}
// 使用例
const toyotaPrice = await getStockPrice('7203.T'); // 東京証券取引所
console.log(`トヨタ株価: ${toyotaPrice.price}円`);
⚠️ 注意: Alpha Vantageは米国株がメイン。日本株は銘柄コードに「.T」を付けて「7203.T」のように指定しますが、データが取得できない場合があります。日本株専用にはYahoo Finance APIやカブドットコム証券APIを検討してください。
アラート条件判定ロジック
ユーザー設定に基づく条件チェック
- 価格ベース: 「3,500円以上」「3,000円以下」などの閾値判定
- 変動率ベース: 「前日比+5%以上」「1時間で-3%以上」
- 出来高ベース: 「平均出来高の200%超え」で急騰・急落を検知
- テクニカル指標: 移動平均線のゴールデンクロス・デッドクロス
- 複合条件: AND/OR条件で複雑なアラート設定
async function checkAlerts() {
// データベースから全アクティブアラートを取得
const alerts = await db.query('SELECT * FROM alerts WHERE active = true');
for (const alert of alerts) {
const stockData = await getStockPrice(alert.symbol);
let shouldTrigger = false;
let message = '';
// 上限価格チェック
if (alert.upper_limit && stockData.price >= alert.upper_limit) {
shouldTrigger = true;
message = `${alert.symbol}が${alert.upper_limit}円を上回りました!現在価格: ${stockData.price}円`;
}
// 下限価格チェック
if (alert.lower_limit && stockData.price <= alert.lower_limit) {
shouldTrigger = true;
message = `${alert.symbol}が${alert.lower_limit}円を下回りました!現在価格: ${stockData.price}円`;
}
// 変動率チェック
if (alert.change_percent && Math.abs(stockData.changePercent) >= alert.change_percent) {
shouldTrigger = true;
message = `${alert.symbol}が${stockData.changePercent}%変動しました!`;
}
// アラート発動
if (shouldTrigger) {
await sendNotification(alert.user_id, message, alert.notification_methods);
await db.query('UPDATE alerts SET last_triggered = NOW() WHERE id = ?', [alert.id]);
}
}
}
// 1分ごとに実行
setInterval(checkAlerts, 60000);
メール通知の実装
SendGridで即座にメール送信
- SendGrid無料枠: 月100通まで無料、それ以降は従量課金
- HTMLメール: 株価チャート画像を埋め込み、視覚的に分かりやすく
- 配信速度: 通常3-5秒以内に届く
- バッチ送信: 複数ユーザーに一括送信でコスト削減
const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
async function sendEmailAlert(userEmail, stockSymbol, price, message) {
const msg = {
to: userEmail,
from: 'alerts@stockalert.com',
subject: `🔔 ${stockSymbol} 株価アラート発動!`,
text: message,
html: `
<div style="font-family: sans-serif; padding: 20px;">
<h2 style="color: #667eea;">🔔 株価アラートが発動しました!</h2>
<div style="background: #f3f4f6; padding: 20px; border-radius: 10px; margin: 20px 0;">
<h3>${stockSymbol}</h3>
<p style="font-size: 24px; font-weight: bold; color: #1f2937;">${price}円</p>
<p>${message}</p>
</div>
<a href="https://yourapp.com/alerts" style="background: #667eea; color: white; padding: 12px 24px; text-decoration: none; border-radius: 8px; display: inline-block;">
アラート管理画面を開く
</a>
</div>
`
};
await sgMail.send(msg);
console.log(`メール送信完了: ${userEmail}`);
}
LINE通知の実装
LINE Messaging APIで即座に通知
- LINE Notify: 最も簡単、個人向けトークンで通知送信
- LINE Messaging API: 本格的なBot、双方向やりとり可能
- リッチメッセージ: 画像やボタン付きメッセージで視認性向上
- 無料枠: 月1,000通まで無料、それ以降は従量課金
const axios = require('axios');
async function sendLineNotify(token, message) {
await axios.post(
'https://notify-api.line.me/api/notify',
`message=${encodeURIComponent(message)}`,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer ${token}`
}
}
);
}
// LINE Messaging API版
const line = require('@line/bot-sdk');
const client = new line.Client({
channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN
});
async function sendLineMessage(userId, stockSymbol, price) {
const message = {
type: 'flex',
altText: `${stockSymbol} 株価アラート`,
contents: {
type: 'bubble',
hero: {
type: 'box',
layout: 'vertical',
contents: [
{
type: 'text',
text: '🔔 株価アラート',
weight: 'bold',
size: 'xl',
color: '#ffffff'
}
],
backgroundColor: '#667eea',
paddingAll: '20px'
},
body: {
type: 'box',
layout: 'vertical',
contents: [
{
type: 'text',
text: stockSymbol,
weight: 'bold',
size: 'lg'
},
{
type: 'text',
text: `${price}円`,
size: 'xxl',
weight: 'bold',
color: '#667eea'
}
]
}
}
};
await client.pushMessage(userId, message);
}
💡 ユーザー体験: LINE通知は開封率が非常に高く(80%以上)、即座に確認されます。メールよりも緊急性の高いアラートに最適です。
プッシュ通知の実装
Firebase Cloud Messaging (FCM)
- 対応プラットフォーム: iOS、Android、Webブラウザ全対応
- 完全無料: 制限なしで無料利用可能
- 到達率: 90%以上の高い到達率
- カスタマイズ: アイコン、音、振動パターンを設定可能
- バックグラウンド通知: アプリが起動していなくても通知が届く
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
async function sendPushNotification(deviceToken, stockSymbol, price, message) {
const payload = {
notification: {
title: `🔔 ${stockSymbol} 株価アラート`,
body: `現在価格: ${price}円 - ${message}`,
icon: '/icon-192x192.png',
badge: '/badge-72x72.png',
sound: 'default',
click_action: 'https://yourapp.com/alerts'
},
data: {
stockSymbol: stockSymbol,
price: price.toString(),
timestamp: new Date().toISOString()
}
};
const response = await admin.messaging().send({
token: deviceToken,
notification: payload.notification,
data: payload.data,
android: {
priority: 'high',
notification: {
sound: 'default',
channelId: 'stock-alerts'
}
},
apns: {
payload: {
aps: {
sound: 'default',
badge: 1
}
}
}
});
console.log('プッシュ通知送信完了:', response);
}
⚠️ 重要: プッシュ通知を使用する場合、ユーザーから通知許可を取得する必要があります。また、iOSではAPNs証明書の設定が必要です。
データベース設計
ユーザーとアラート情報の管理
- users テーブル: ユーザー情報、通知設定
- alerts テーブル: アラート条件、監視銘柄
- alert_history テーブル: 過去の発動履歴
- stocks テーブル: 銘柄マスターデータ
- stock_prices テーブル: 過去の株価データ(分析用)
-- ユーザーテーブル CREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, line_user_id VARCHAR(255), fcm_token TEXT, notification_email BOOLEAN DEFAULT true, notification_line BOOLEAN DEFAULT false, notification_push BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT NOW() ); -- アラートテーブル CREATE TABLE alerts ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, stock_symbol VARCHAR(20) NOT NULL, stock_name VARCHAR(100), upper_limit DECIMAL(10,2), lower_limit DECIMAL(10,2), change_percent DECIMAL(5,2), volume_multiplier DECIMAL(4,2), active BOOLEAN DEFAULT true, last_triggered TIMESTAMP, created_at TIMESTAMP DEFAULT NOW(), INDEX idx_user_active (user_id, active), INDEX idx_stock_active (stock_symbol, active) ); -- 発動履歴テーブル CREATE TABLE alert_history ( id SERIAL PRIMARY KEY, alert_id INTEGER REFERENCES alerts(id) ON DELETE CASCADE, trigger_price DECIMAL(10,2), trigger_type VARCHAR(50), message TEXT, triggered_at TIMESTAMP DEFAULT NOW(), INDEX idx_alert_time (alert_id, triggered_at) ); -- 銘柄マスターテーブル CREATE TABLE stocks ( symbol VARCHAR(20) PRIMARY KEY, name VARCHAR(100) NOT NULL, market VARCHAR(50), sector VARCHAR(100), updated_at TIMESTAMP DEFAULT NOW() );
フロントエンド実装
直感的なアラート設定UI
- 銘柄検索: 銘柄コードや会社名で検索、サジェスト機能
- リアルタイム価格表示: WebSocketで株価を自動更新
- ビジュアライゼーション: Chart.jsでミニチャート表示
- アラート管理: 一覧表示、編集、削除、一時停止
- 通知履歴: 過去の発動履歴を時系列表示
import { useState, useEffect } from 'react';
import io from 'socket.io-client';
function StockAlertDashboard() {
const [alerts, setAlerts] = useState([]);
const [stockPrices, setStockPrices] = useState({});
useEffect(() => {
// WebSocketで株価をリアルタイム受信
const socket = io('ws://localhost:3000');
socket.on('price-update', (data) => {
setStockPrices(prev => ({
...prev,
[data.symbol]: data
}));
});
// アラート一覧を取得
fetchAlerts();
return () => socket.disconnect();
}, []);
async function fetchAlerts() {
const res = await fetch('/api/alerts');
const data = await res.json();
setAlerts(data);
}
async function createAlert(alertData) {
await fetch('/api/alerts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(alertData)
});
fetchAlerts();
}
return (
<div className="dashboard">
<h1>株価アラート管理</h1>
{/* アラート設定フォーム */}
<AlertForm onSubmit={createAlert} />
{/* アクティブなアラート一覧 */}
<div className="alert-list">
{alerts.map(alert => (
<AlertCard
key={alert.id}
alert={alert}
currentPrice={stockPrices[alert.stock_symbol]?.price}
/>
))}
</div>
</div>
);
}
スケーラビリティと最適化
ユーザー増加に耐えるシステム設計
- バッチ処理: 同じ銘柄のアラートをまとめて1回のAPI呼び出しで処理
- 優先度キュー: 発動頻度の高いアラートを優先的にチェック
- 分散処理: 複数サーバーで銘柄を分散監視
- 負荷分散: AWS ELB / Nginx でトラフィックを分散
- データベース最適化: インデックス追加、読み取りレプリカ
- 通知キュー: RabbitMQ / AWS SQS で通知を非同期処理
async function batchCheckAlerts() {
// アクティブなアラートをすべて取得
const alerts = await db.query(`
SELECT DISTINCT stock_symbol
FROM alerts
WHERE active = true
`);
// 銘柄ごとにグループ化
const symbolGroups = {};
for (const alert of alerts) {
if (!symbolGroups[alert.stock_symbol]) {
symbolGroups[alert.stock_symbol] = [];
}
symbolGroups[alert.stock_symbol].push(alert);
}
// 並列で株価取得(最大10銘柄ずつ)
const symbols = Object.keys(symbolGroups);
const chunks = chunkArray(symbols, 10);
for (const chunk of chunks) {
await Promise.all(
chunk.map(async (symbol) => {
const price = await getStockPrice(symbol);
// その銘柄の全アラートをチェック
for (const alert of symbolGroups[symbol]) {
await checkAndTriggerAlert(alert, price);
}
})
);
// APIレート制限対策で1秒待機
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
function chunkArray(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
✅ 最適化効果: この方法なら、1,000人のユーザーが100銘柄を監視していても、重複を除いて100回のAPI呼び出しで済みます。
コスト試算とマネタイズ
持続可能なビジネスモデル
- Alpha Vantage: 無料枠で月500リクエスト、有料は月$49.99〜
- SendGrid: 月100通まで無料、追加は1,000通あたり$14.95
- LINE Messaging API: 月1,000通まで無料、追加は1,000通あたり¥350
- Firebase FCM: 完全無料
- サーバーコスト: AWS EC2 t3.micro(月$10)+ RDS(月$15)
- 総コスト: 月約$50-100で運用可能
💡 価格設定例:
• 無料プラン: 3銘柄、5アラートまで
• ベーシック(月980円): 10銘柄、無制限アラート
• プロ(月2,980円): 無制限銘柄、テクニカル分析、優先サポート
• エンタープライズ(要相談): API提供、専用サーバー
✅ 収益シミュレーション: 月間500ユーザーのうち20%が有料プラン(平均1,500円)に転換すれば、月商15万円。1,000ユーザーで月商30万円を達成できます。
今日から始めるMVP
3日間で動くプロトタイプを作る
- Day 1: Next.jsでUI構築、Alpha Vantage APIで株価取得を実装
- Day 2: PostgreSQLでデータベース構築、アラート判定ロジック実装
- Day 3: SendGridでメール通知実装、デプロイ(Vercel + Railway)
// pages/api/check-alerts.js
import { getStockPrice } from '@/lib/alpha-vantage';
import { sendEmail } from '@/lib/sendgrid';
import db from '@/lib/database';
export default async function handler(req, res) {
// アクティブなアラートを取得
const alerts = await db.query(`
SELECT a.*, u.email
FROM alerts a
JOIN users u ON a.user_id = u.id
WHERE a.active = true
`);
let triggeredCount = 0;
for (const alert of alerts) {
const stock = await getStockPrice(alert.stock_symbol);
// 上限チェック
if (alert.upper_limit && stock.price >= alert.upper_limit) {
await sendEmail(
alert.email,
`${alert.stock_symbol} が ${alert.upper_limit}円を突破!`,
`現在価格: ${stock.price}円`
);
triggeredCount++;
}
// 下限チェック
if (alert.lower_limit && stock.price <= alert.lower_limit) {
await sendEmail(
alert.email,
`${alert.stock_symbol} が ${alert.lower_limit}円を下回った!`,
`現在価格: ${stock.price}円`
);
triggeredCount++;
}
}
res.json({ success: true, triggered: triggeredCount });
}
// Vercel Cronで1分ごとに実行
// vercel.json に設定:
// {
// "crons": [{
// "path": "/api/check-alerts",
// "schedule": "* * * * *"
// }]
// }
⚠️ 最初の一歩: 完璧を目指さず、まず「1銘柄、メール通知のみ」の最小機能を完成させましょう。ユーザーフィードバックを得てから機能を追加する方が成功確率が高まります。
✅ ローンチのヒント: Product Hunt、Reddit(r/investing、r/stocks)、Twitter(#投資 #株式)で公開すれば、初日から数百人のユーザーを獲得できる可能性があります。
