# تطبيق تحليل مالي للبيانات من Investing
## مكونات المشروع
### 1. الواجهة الأمامية (HTML, CSS, JavaScript)
#### index.html
```html
محلل البيانات المالية
```
#### style.css
```css
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap');
:root {
--primary-color: #2c73d2;
--secondary-color: #4e8fef;
--background-color: #f8f9fa;
--text-color: #333;
--border-color: #ddd;
--shadow-color: rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Tajawal', sans-serif;
background-color: var(--background-color);
color: var(--text-color);
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
h1, h2, h3 {
margin-bottom: 20px;
color: var(--primary-color);
}
h1 {
text-align: center;
font-size: 2.5rem;
margin: 1.5rem 0;
}
.upload-section {
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 5px 15px var(--shadow-color);
margin-bottom: 30px;
}
.file-upload {
margin: 20px 0;
}
.file-upload input[type="file"] {
position: absolute;
width: 0;
height: 0;
overflow: hidden;
}
.file-upload label {
display: inline-block;
padding: 12px 24px;
background: var(--primary-color);
color: white;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
}
.file-upload label:hover {
background: var(--secondary-color);
}
.options {
margin: 20px 0;
}
.option {
margin: 10px 0;
display: flex;
align-items: center;
}
.option input[type="checkbox"] {
margin-left: 10px;
}
button {
display: block;
width: 100%;
padding: 12px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 5px;
font-size: 1rem;
cursor: pointer;
transition: background 0.3s;
}
button:hover {
background: var(--secondary-color);
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.results {
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 5px 15px var(--shadow-color);
}
.charts {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 30px;
}
.chart-container {
flex: 1 1 100%;
min-height: 300px;
border: 1px solid var(--border-color);
border-radius: 5px;
padding: 15px;
}
@media (min-width: 768px) {
.chart-container {
flex: 1 1 45%;
}
}
.stats, .recommendations {
margin-top: 30px;
padding: 20px;
border: 1px solid var(--border-color);
border-radius: 5px;
}
#statsContent, #recommendationsContent {
display: grid;
grid-template-columns: 1fr;
gap: 15px;
}
@media (min-width: 768px) {
#statsContent, #recommendationsContent {
grid-template-columns: 1fr 1fr;
}
}
.stat-item, .recommendation-item {
padding: 15px;
background: #f5f7fa;
border-radius: 5px;
box-shadow: 0 2px 5px var(--shadow-color);
}
.stat-value {
font-weight: bold;
font-size: 1.1rem;
color: var(--primary-color);
}
```
#### app.js
```javascript
document.addEventListener('DOMContentLoaded', function() {
const csvFileInput = document.getElementById('csvFile');
const analyzeBtn = document.getElementById('analyzeBtn');
const resultsSection = document.getElementById('results');
// Charts
let priceChart = null;
let indicatorsChart = null;
csvFileInput.addEventListener('change', function() {
if (this.files.length > 0) {
analyzeBtn.disabled = false;
} else {
analyzeBtn.disabled = true;
}
});
analyzeBtn.addEventListener('click', function() {
const file = csvFileInput.files[0];
if (file) {
// Parse the CSV file
Papa.parse(file, {
header: true,
complete: function(results) {
processData(results.data);
}
});
}
});
function processData(data) {
// Extract relevant information from the data
const dates = [];
const prices = [];
let volumes = [];
// Investing.com CSV format typically has these columns
data.forEach((row) => {
// Check for the presence of these columns (adjust if needed based on your CSV format)
if (row['تاريخ'] && row['سعر الاغلاق']) {
dates.unshift(row['تاريخ']);
prices.unshift(parseFloat(row['سعر الاغلاق'].replace(',', '')));
if (row['الحجم']) {
volumes.unshift(parseInt(row['الحجم'].replace(',', '')));
}
} else if (row['Date'] && row['Price']) { // English column names
dates.unshift(row['Date']);
prices.unshift(parseFloat(row['Price'].replace(',', '')));
if (row['Vol.']) {
volumes.unshift(parseInt(row['Vol.'].replace(',', '')));
}
}
});
// Calculate indicators
const ma20 = calculateMA(prices, 20);
const ma50 = calculateMA(prices, 50);
const ma200 = calculateMA(prices, 200);
const rsiValues = calculateRSI(prices, 14);
const macdValues = calculateMACD(prices);
const volatility = calculateVolatility(prices, 20);
// Display results
resultsSection.style.display = 'block';
// Draw price chart
drawPriceChart(dates, prices, ma20, ma50, ma200);
// Draw indicators chart
drawIndicatorsChart(dates, rsiValues, macdValues.macd, macdValues.signal);
// Generate statistics
displayStatistics(prices, volumes, volatility, rsiValues, macdValues);
// Generate recommendations
displayRecommendations(prices, ma20, ma50, ma200, rsiValues, macdValues);
}
function calculateMA(data, period) {
const result = [];
for (let i = 0; i < data.length; i++) {
if (i < period - 1) {
result.push(null);
continue;
}
let sum = 0;
for (let j = 0; j < period; j++) {
sum += data[i - j];
}
result.push(sum / period);
}
return result;
}
function calculateRSI(prices, period) {
const rsi = [];
const deltas = [];
// Calculate price changes
for (let i = 1; i < prices.length; i++) {
deltas.push(prices[i] - prices[i - 1]);
}
// Initialize RSI values
for (let i = 0; i < period; i++) {
rsi.push(null);
}
// Calculate RSI for each window
for (let i = period; i < deltas.length + 1; i++) {
const windowDeltas = deltas.slice(i - period, i);
let gains = 0;
let losses = 0;
windowDeltas.forEach(delta => {
if (delta > 0) {
gains += delta;
} else {
losses -= delta;
}
});
const avgGain = gains / period;
const avgLoss = losses / period;
let rs = 0;
if (avgLoss !== 0) {
rs = avgGain / avgLoss;
}
rsi.push(100 - (100 / (1 + rs)));
}
return rsi;
}
function calculateMACD(prices, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) {
// Calculate EMAs
const emaFast = calculateEMA(prices, fastPeriod);
const emaSlow = calculateEMA(prices, slowPeriod);
// Calculate MACD line
const macdLine = [];
for (let i = 0; i < prices.length; i++) {
if (emaFast[i] !== null && emaSlow[i] !== null) {
macdLine.push(emaFast[i] - emaSlow[i]);
} else {
macdLine.push(null);
}
}
// Calculate signal line (9-day EMA of MACD line)
const signalLine = calculateEMA(macdLine, signalPeriod);
// Calculate histogram
const histogram = [];
for (let i = 0; i < macdLine.length; i++) {
if (macdLine[i] !== null && signalLine[i] !== null) {
histogram.push(macdLine[i] - signalLine[i]);
} else {
histogram.push(null);
}
}
return {
macd: macdLine,
signal: signalLine,
histogram: histogram
};
}
function calculateEMA(data, period) {
const ema = [];
const multiplier = 2 / (period + 1);
// Initialize EMA with SMA
let sma = 0;
for (let i = 0; i < period; i++) {
sma += data[i];
ema.push(null);
}
sma /= period;
ema[period - 1] = sma;
// Calculate EMA for remaining data
for (let i = period; i < data.length; i++) {
ema.push((data[i] - ema[i - 1]) * multiplier + ema[i - 1]);
}
return ema;
}
function calculateVolatility(prices, period) {
if (prices.length < period) {
return null;
}
const returns = [];
for (let i = 1; i < prices.length; i++) {
returns.push((prices[i] / prices[i - 1]) - 1);
}
const meanReturn = returns.reduce((a, b) => a + b, 0) / returns.length;
const squaredDiffs = returns.map(r => Math.pow(r - meanReturn, 2));
const variance = squaredDiffs.reduce((a, b) => a + b, 0) / squaredDiffs.length;
// Annualized volatility (assuming daily data)
return Math.sqrt(variance) * Math.sqrt(252) * 100;
}
function drawPriceChart(dates, prices, ma20, ma50, ma200) {
const ctx = document.getElementById('priceChart').getContext('2d');
if (priceChart) {
priceChart.destroy();
}
priceChart = new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [
{
label: 'السعر',
data: prices,
borderColor: 'rgba(44, 115, 210, 1)',
backgroundColor: 'rgba(44, 115, 210, 0.1)',
fill: true,
tension: 0.1
},
{
label: 'المتوسط المتحرك 20 يوم',
data: ma20,
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 2,
fill: false,
tension: 0.1
},
{
label: 'المتوسط المتحرك 50 يوم',
data: ma50,
borderColor: 'rgba(255, 159, 64, 1)',
borderWidth: 2,
fill: false,
tension: 0.1
},
{
label: 'المتوسط المتحرك 200 يوم',
data: ma200,
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 2,
fill: false,
tension: 0.1
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
ticks: {
maxTicksLimit: 10
}
}
},
interaction: {
mode: 'index',
intersect: false
}
}
});
}
function drawIndicatorsChart(dates, rsiValues, macdValues, signalValues) {
const ctx = document.getElementById('indicatorsChart').getContext('2d');
if (indicatorsChart) {
indicatorsChart.destroy();
}
indicatorsChart = new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [
{
label: 'مؤشر القوة النسبية (RSI)',
data: rsiValues,
borderColor: 'rgba(153, 102, 255, 1)',
backgroundColor: 'rgba(153, 102, 255, 0.2)',
yAxisID: 'rsi',
fill: true
},
{
label: 'MACD',
data: macdValues,
borderColor: 'rgba(54, 162, 235, 1)',
backgroundColor: 'rgba(54, 162, 235, 0.2)',
yAxisID: 'macd'
},
{
label: 'إشارة MACD',
data: signalValues,
borderColor: 'rgba(255, 99, 132, 1)',
backgroundColor: 'rgba(255, 99, 132, 0.2)',
yAxisID: 'macd'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
ticks: {
maxTicksLimit: 10
}
},
rsi: {
type: 'linear',
position: 'left',
min: 0,
max: 100,
grid: {
drawOnChartArea: false
},
title: {
display: true,
text: 'RSI'
}
},
macd: {
type: 'linear',
position: 'right',
grid: {
drawOnChartArea: false
},
title: {
display: true,
text: 'MACD'
}
}
},
interaction: {
mode: 'index',
intersect: false
}
}
});
}
function displayStatistics(prices, volumes, volatility, rsiValues, macdValues) {
const statsContent = document.getElementById('statsContent');
// Filter out null values
const filteredRSI = rsiValues.filter(val => val !== null);
const filteredMACD = macdValues.macd.filter(val => val !== null);
// Calculate statistics
const currentPrice = prices[prices.length - 1];
const priceChange = prices[prices.length - 1] - prices[prices.length - 2];
const priceChangePercent = (priceChange / prices[prices.length - 2]) * 100;
const lastRSI = filteredRSI[filteredRSI.length - 1];
const lastMACD = filteredMACD[filteredMACD.length - 1];
// Calculate 52-week high and low
const yearPrices = prices.slice(-252); // Assuming 252 trading days in a year
const high52Week = Math.max(...yearPrices);
const low52Week = Math.min(...yearPrices);
// Average volume (if available)
let avgVolume = 'غير متوفر';
if (volumes.length > 0) {
const monthVolumes = volumes.slice(-30); // Last 30 days
avgVolume = Math.round(monthVolumes.reduce((a, b) => a + b, 0) / monthVolumes.length).toLocaleString();
}
statsContent.innerHTML = `
محلل البيانات المالية
تحميل ملف CSV من Investing
السعر الحالي
${currentPrice.toFixed(2)}
التغير اليومي
${priceChange.toFixed(2)} (${priceChangePercent.toFixed(2)}%)
أعلى سعر (52 أسبوع)
${high52Week.toFixed(2)}
أدنى سعر (52 أسبوع)
${low52Week.toFixed(2)}
متوسط حجم التداول (30 يوم)
${avgVolume}
مؤشر القوة النسبية (RSI)
${lastRSI.toFixed(2)}
مؤشر MACD
<