maher-tradingview-api
Version:
Tradingview instant stocks API, indicator alerts, trading bot, and more !
246 lines (212 loc) • 8.25 kB
JavaScript
/* eslint-disable linebreak-style */
/* eslint-disable no-multi-spaces */
/* eslint-disable linebreak-style */
const express = require('express');
const path = require('path');
const TradingView = require('../main');
const axios = require('axios');
const https = require('https');
const { promisify } = require('util');
const app = express();
const PORT = process.env.PORT || 3000;
// Load environment variables
require('dotenv').config();
// API Keys from environment variables
const API_KEYS = {
ALPHAVANTAGE: process.env.ALPHAVANTAGE_API_KEY,
FINNHUB: process.env.FINNHUB_API_KEY,
IEX: process.env.IEX_API_KEY
};
// Validate API keys
if (!API_KEYS.ALPHAVANTAGE || !API_KEYS.FINNHUB || !API_KEYS.IEX) {
console.warn('Warning: Some API keys are missing. Check your .env file');
}
// Create a custom axios instance with longer timeout
const apiClient = axios.create({
timeout: 30000, // 30 second timeout
httpsAgent: new https.Agent({ keepAlive: true })
});
// Set EJS as the view engine
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Middleware setup
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
// CORS and performance middleware
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Cache-Control', 'public, max-age=300'); // كاش لمدة 5 دقائق
next();
});
// Root route
app.get('/', (req, res) => {
res.render('index', { title: 'الصفحة الرئيسية' });
});
// POST route handler for /market-data
app.post('/market-data', async (req, res) => {
try {
const { symbol, timeframe } = req.body;
if (!symbol) {
return res.status(400).render('error', {
title: 'خطأ',
message: 'يجب تحديد رمز السهم',
error: {}
});
}
// الحصول على بيانات السوق
const data = await getMarketData(symbol, timeframe || '1d');
// عرض صفحة بيانات السوق مع البيانات المجلوبة
res.render('market-data-clean', {
title: `بيانات السوق لـ ${symbol}`,
symbol,
timeframe: timeframe || '1d',
data: { data }
});
} catch (error) {
console.error('خطأ في معالجة بيانات السوق:', error);
res.render('error', {
title: 'خطأ',
message: 'حدث خطأ في معالجة البيانات',
error: process.env.NODE_ENV === 'development' ? error : {}
});
}
});
// تحسين معالجة الأخطاء
const errorHandler = (err, req, res, next) => {
console.error('خطأ في الخادم:', err);
if (res.headersSent) {
return next(err);
}
res.status(500).render('error', {
title: 'خطأ في الخادم',
message: 'حدث خطأ أثناء معالجة طلبك. يرجى المحاولة مرة أخرى.',
error: process.env.NODE_ENV === 'development' ? err : {}
});
};
app.use(errorHandler);
// التعامل مع طلبات البيانات
app.get('/api/market-data/:symbol', async (req, res) => {
try {
const { symbol } = req.params;
const { timeframe = '1d' } = req.query;
// محاولة الحصول على البيانات من المصادر المختلفة
const data = await getMarketData(symbol, timeframe);
if (!data || !data.data || data.data.length === 0) {
return res.status(404).json({
error: 'لم يتم العثور على بيانات تاريخية',
symbol,
timeframe
});
}
res.json(data);
} catch (error) {
console.error('خطأ في الحصول على بيانات السوق:', error);
res.status(500).json({
error: 'حدث خطأ في الحصول على بيانات السوق',
details: process.env.NODE_ENV === 'development' ? error.message : undefined
});
}
});
// وظيفة للحصول على بيانات السوق من مصادر مختلفة
async function getMarketData(symbol, timeframe) {
// محاولة الحصول على البيانات من Alpha Vantage أولاً
try {
const response = await apiClient.get(
`https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=${symbol}&apikey=${API_KEYS.ALPHAVANTAGE}`
);
if (response.data && response.data['Time Series (Daily)']) {
const timeSeriesData = response.data['Time Series (Daily)'];
const data = {
symbol: symbol,
data: Object.entries(timeSeriesData).map(([date, values]) => ({
time: date,
open: parseFloat(values['1. open']),
high: parseFloat(values['2. high']),
low: parseFloat(values['3. low']),
close: parseFloat(values['4. close']),
volume: parseFloat(values['5. volume'])
})).sort((a, b) => new Date(b.time) - new Date(a.time))
};
return data;
}
} catch (error) {
console.warn('فشل الحصول على البيانات من Alpha Vantage:', error.message);
}
// محاولة الحصول على البيانات من Finnhub
try {
const to = Math.floor(Date.now() / 1000);
const from = to - (365 * 24 * 60 * 60); // سنة واحدة
const response = await apiClient.get(
`https://finnhub.io/api/v1/stock/candle?symbol=${symbol}&resolution=D&from=${from}&to=${to}&token=${API_KEYS.FINNHUB}`
);
if (response.data && response.data.s === 'ok' && response.data.t) {
const data = {
symbol: symbol,
data: response.data.t.map((timestamp, i) => ({
time: new Date(timestamp * 1000).toISOString().split('T')[0],
open: response.data.o[i],
high: response.data.h[i],
low: response.data.l[i],
close: response.data.c[i],
volume: response.data.v[i]
})).sort((a, b) => new Date(b.time) - new Date(a.time))
};
return data;
}
} catch (error) {
console.warn('فشل الحصول على البيانات من Finnhub:', error.message);
}
// إذا فشلت كل المصادر
return null;
}
// مسار صفحة معلومات السهم
app.get('/stock/:symbol', async (req, res) => {
try {
const { symbol } = req.params;
const data = await getMarketData(symbol, '1d');
res.render('stock-details', {
title: `معلومات السهم ${symbol}`,
symbol,
data,
error: null
});
} catch (error) {
console.error('خطأ في تحميل معلومات السهم:', error);
res.render('stock-details', {
title: 'خطأ في تحميل معلومات السهم',
symbol: req.params.symbol,
data: null,
error: 'حدث خطأ في تحميل بيانات السهم'
});
}
});
// مسار API للحصول على البيانات التاريخية
app.get('/api/stock-history/:symbol', async (req, res) => {
try {
const { symbol } = req.params;
const { from, to } = req.query;
// استخدام TradingView للحصول على البيانات التاريخية
const client = new TradingView.Client();
const chart = new client.Session.Chart();
await chart.setSymbol(symbol);
await chart.setTimeframe('D'); // يومي
if (from && to) {
await chart.setRange(new Date(from), new Date(to));
}
const data = await chart.getMarketData();
client.end();
res.json(data);
} catch (error) {
console.error('خطأ في جلب البيانات التاريخية:', error);
res.status(500).json({
error: 'فشل في جلب البيانات التاريخية',
details: process.env.NODE_ENV === 'development' ? error.message : undefined
});
}
});
// Start the server
app.listen(PORT, () => {
console.log(`الخادم يعمل على المنفذ ${PORT}`);
});