- name
- thebig-gavin-marketing-dashboard
- description
- Real-time financial market research cockpit aggregating CN/HK/US indices, commodities, treasury yields, sector hotspots, capital flows, 7×24 news, and AI token usage trends in a single screen dashboard.
- triggers
- ["set up a financial market research dashboard","build a real-time stock market monitoring cockpit","create a multi-market data visualization dashboard","integrate financial data from multiple sources","display A-share Hong Kong and US stock indices","track commodity prices and treasury yields in real-time","build an industry chain watchlist dashboard","monitor AI model token usage trends"]
# theBigGavin/marketingdashboard
> Skill by [ara.so](https://ara.so) — Marketing Skills collection.
A comprehensive real-time market research cockpit that aggregates financial data from multiple sources into a single-screen dashboard. Built with React 19, Vite, TypeScript, and Tailwind CSS, it provides live tracking of A-share/Hong Kong/US stock indices, commodities, US treasury yields, sector hotspots, capital flows, 7×24 financial news, industry chain watchlists, and AI model token consumption trends.
## What It Does
The Marketing Dashboard is a zero-dependency data service that:
- **Multi-Market Coverage**: Real-time quotes for Shanghai/Shenzhen, Hang Seng, Dow Jones, NASDAQ, S&P 500, VIX, and USD/CNY
- **Commodities & Crypto**: Live prices for gold, silver, copper, crude oil, and Bitcoin with intraday charts
- **Treasury Monitoring**: 10Y/2Y yields, 2s10s spread, yield curve shapes with historical monthly data
- **Sector Analysis**: Industry/concept board rankings with constituent stocks, leading stocks, and capital flows
- **Capital Flow Tracking**: Top net inflow stocks, sector capital flow minute-level curves, hot/gainer/loser lists
- **Industry Chains**: Semiconductor, AI computing, new energy vehicles, robotics, pharma innovation with upstream/midstream/downstream stocks
- **AI Cockpit**: OpenRouter daily leaderboard tracking 50+ AI model providers' token consumption trends (7d~1y, 60+ day historical lookback)
- **Commodity Prices**: Precious metals, base metals, energy, agricultural products futures trends with spot price comparisons
- **News Aggregation**: 7×24 global financial news with macro keyword highlighting
- **PWA Support**: Installable as desktop application with offline caching
## Installation
### Prerequisites
- Node.js 18+
- System with `curl` available (for proxy endpoints)
### Local Development
```bash
# Clone the repository
git clone https://github.com/theBigGavin/marketingdashboard.git
cd marketingdashboard
# Install dependencies
npm install
# Start development server
npm run dev
```
- Frontend dev server: http://localhost:3000
- Data proxy service: http://localhost:3001 (Vite auto-proxies `/api` requests)
### Production Deployment
```bash
# Build for production
npm run build
# Optional: Configure OpenRouter API Key for AI dashboard
echo 'OPENROUTER_API_KEY=sk-or-v1-xxxx' > server/.env
# Start production server (serves both API and static files)
npm start
```
Access at http://localhost:3000
### Docker Deployment
```bash
docker build -t market-cockpit .
docker run -p 3000:3000 market-cockpit
```
### Environment Variables
Create `server/.env` for optional API keys:
```env
# Optional: OpenRouter API key for AI dashboard
OPENROUTER_API_KEY=sk-or-v1-your-key-here
# Optional: Custom port (default: 3000)
PORT=3000
```
## API Reference
All APIs are accessed via `/api` prefix and include built-in caching and rate limiting:
### Market Data
```typescript
// Get real-time quotes for indices/stocks
GET /api/quotes?codes=sh000001,hk.00700,us.AAPL
// Response format
{
"sh000001": {
"code": "sh000001",
"name": "上证指数",
"price": 3250.12,
"change": 15.32,
"percent": 0.47,
"volume": "285.6亿",
"open": 3245.80,
"high": 3255.60,
"low": 3242.10
}
}
```
```typescript
// Get intraday minute chart
GET /api/minute?code=sh000001
// Response: array of [timestamp, price, volume]
[
["09:30", 3245.80, 12500000],
["09:31", 3246.20, 13200000],
// ...
]
```
### Sector & Board Data
```typescript
// Get sector rankings
GET /api/boards?type=industry&dir=desc&n=20
// Get board constituent stocks
GET /api/board-stocks?code=BK0447&n=50
// Response format
{
"stocks": [
{
"code": "300750",
"name": "宁德时代",
"price": 235.60,
"percent": 2.35
}
]
}
```
### Futures & Commodities
```typescript
// Get commodity/crypto quotes
GET /api/futures?list=GC00Y,CL00Y,BTCUSD
// Get futures intraday chart
GET /api/future-minute?code=nf_AU0
// Get futures daily K-line (up to 400 bars)
GET /api/future-daily?code=nf_AU0&n=90
```
### Capital Flow
```typescript
// Get top net inflow stocks
GET /api/moneyflow?n=50
// Get batch stock capital flows
GET /api/stock-flows?codes=300750,600519
// Get sector capital flow curves
GET /api/board-flow?n=100
```
### Treasury Data
```typescript
// Get current treasury yields
GET /api/treasuries
// Response format
{
"2Y": 4.25,
"10Y": 4.15,
"spread_2s10s": -0.10,
"timestamp": "2026-07-31T10:00:00Z"
}
// Get historical yield curves (2001-present)
GET /api/treasury-history
```
### News & Search
```typescript
// Get 7×24 financial news
GET /api/news?page=1&size=50
// Search stocks by name/pinyin
GET /api/stock-search?q=宁德
// Get stock's associated boards
GET /api/stock-boards?code=300750
```
### Industry Chain & AI
```typescript
// Query stocks by concept/industry (using Wencai)
GET /api/mystery-select?query=人工智能&limit=50
// Parse industry chain text (auto-categorize upstream/midstream/downstream)
POST /api/chain-parse
Content-Type: application/json
{
"text": "上游:芯片设计\n中游:封装测试\n下游:终端应用"
}
// Get OpenRouter daily usage leaderboard
GET /api/openrouter-usage
```
## Code Examples
### Using the API Client
```typescript
// src/lib/api.ts - API client examples
import { fetchQuotes, fetchMinuteChart, fetchBoardStocks } from './lib/api';
// Fetch multiple quotes
const quotes = await fetchQuotes(['sh000001', 'hk.HSI', 'us.DJI']);
console.log(quotes['sh000001'].price);
// Fetch minute chart
const chart = await fetchMinuteChart('sh000001');
chart.forEach(([time, price, volume]) => {
console.log(`${time}: ${price}`);
});
// Fetch board constituent stocks
const stocks = await fetchBoardStocks('BK0447', 30);
stocks.forEach(stock => {
console.log(`${stock.name}: ${stock.percent}%`);
});
```
### Creating a Custom Panel Component
```typescript
// src/components/dash/CustomPanel.tsx
import React, { useEffect, useState } from 'react';
import { usePolling } from '../../hooks/usePolling';
import { fetchQuotes } from '../../lib/api';
interface Quote {
code: string;
name: string;
price: number;
percent: number;
}
export default function CustomPanel() {
const [quotes, setQuotes] = useState<Record<string, Quote>>({});
// Poll every 5 seconds
usePolling(async () => {
const data = await fetchQuotes(['sh000001', 'hk.HSI']);
setQuotes(data);
}, 5000);
return (
<div className="bg-gray-900 rounded-lg p-4">
<h3 className="text-lg font-semibold mb-3 text-white">Market Indices</h3>
<div className="space-y-2">
{Object.values(quotes).map(quote => (
<div key={quote.code} className="flex justify-between items-center">
<span className="text-gray-300">{quote.name}</span>
<div className="text-right">
<div className="text-white font-mono">{quote.price.toFixed(2)}</div>
<div className={quote.percent >= 0 ? 'text-red-500' : 'text-green-500'}>
{quote.percent >= 0 ? '+' : ''}{quote.percent.toFixed(2)}%
</div>
</div>
</div>
))}
</div>
</div>
);
}
```
### Using the Unified Market Data Center
```typescript
// src/lib/market.ts - Unified quote center
import { market } from './lib/market';
// Subscribe to market data updates
const unsubscribe = market.subscribe((quotes) => {
console.log('Latest quotes:', quotes);
// All panels receive the same snapshot, ensuring consistency
});
// Add codes to watch
market.addCodes(['sh000001', 'hk.00700', 'us.AAPL']);
// Get current quote
const quote = market.getQuote('sh000001');
console.log(`${quote.name}: ${quote.price} (${quote.percent}%)`);
// Cleanup
unsubscribe();
```
### Creating a Watchlist with Search
```typescript
// Using the WatchlistPanel component
import WatchlistPanel from './components/dash/WatchlistPanel';
import { fetchStockSearch } from './lib/api';
// Search for stocks
const searchStocks = async (query: string) => {
const results = await fetchStockSearch(query);
// results: Array<{ code: string; name: string }>
return results;
};
// Add to watchlist (stored in localStorage)
const addToWatchlist = (code: string, name: string) => {
const watchlist = JSON.parse(localStorage.getItem('watchlist') || '[]');
watchlist.push({ code, name });
localStorage.setItem('watchlist', JSON.stringify(watchlist));
};
```
### Fetching AI Model Usage Data
```typescript
// Fetch OpenRouter daily leaderboard
import { fetchOpenRouterUsage } from './lib/api';
const usageData = await fetchOpenRouterUsage();
// Response includes daily token consumption by provider
// Data is cached and accumulated over time on server
usageData.forEach(entry => {
console.log(`${entry.date}: ${entry.provider} - ${entry.tokens} tokens`);
});
```
### Adding a New Data Source
```typescript
// server/index.cjs - Add new API endpoint
// Inside the request handler:
if (url === '/api/custom-data') {
const cacheKey = 'custom-data';
const cached = cache.get(cacheKey);
if (cached) {
sendJSON(res, cached);
return;
}
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
cache.set(cacheKey, data, 60); // Cache for 60 seconds
sendJSON(res, data);
} catch (error) {
console.error('Error fetching custom data:', error);
sendJSON(res, { error: 'Failed to fetch data' }, 500);
}
return;
}
```
### Creating a Custom Spark Chart
```typescript
// src/components/dash/Spark.tsx - Mini chart component
import Spark from './components/dash/Spark';
// Usage in your panel
<Spark
data={minuteData} // Array of [time, price, volume]
mode="a-stock" // 'a-stock' | '24h' | 'daily'
color={percent >= 0 ? 'red' : 'green'}
height={60}
/>
```
## Configuration
### Market Indices Configuration
Edit `src/config/indices.ts` to customize tracked indices:
```typescript
export const INDICES = [
{ code: 'sh000001', name: '上证指数', market: 'CN' },
{ code: 'sz399001', name: '深证成指', market: 'CN' },
{ code: 'hk.HSI', name: '恒生指数', market: 'HK' },
{ code: 'us.DJI', name: '道琼斯', market: 'US' },
// Add custom indices
];
```
### Commodity Configuration
Edit `src/config/commodities.ts`:
```typescript
export const COMMODITIES = [
{ code: 'GC00Y', name: '纽约黄金', unit: '美元/盎司' },
{ code: 'BTCUSD', name: '比特币', unit: 'USDT' },
// Add custom commodities
];
```
### Industry Chain Configuration
View on GitHub