import React, { useState } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import Papa from 'papaparse';
import _ from 'lodash';
const BollingerBandsAnalyzer = () => {
const [file, setFile] = useState(null);
const [data, setData] = useState([]);
const [bollingerData, setBollingerData] = useState([]);
const [status, setStatus] = useState('');
const [prediction, setPrediction] = useState(null);
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [showResults, setShowResults] = useState(false);
const handleFileChange = (e) => {
if (e.target.files[0]) {
setFile(e.target.files[0]);
setStatus('تم اختيار الملف: ' + e.target.files[0].name);
setShowResults(false);
}
};
const calculateBollingerBands = (prices, period = 20, stdDev = 2) => {
// التأكد من وجود بيانات كافية
if (prices.length < period) {
setStatus('عدد البيانات غير كافٍ لحساب البولينجر باند');
return [];
}
const result = [];
for (let i = 0; i < prices.length; i++) {
if (i < period - 1) {
// لا يمكن حساب المتوسط المتحرك للعناصر الأولى
result.push({
price: prices[i],
middle: null,
upper: null,
lower: null
});
} else {
// حساب المتوسط المتحرك لفترة محددة
const slice = prices.slice(i - period + 1, i + 1);
const sma = slice.reduce((sum, price) => sum + price, 0) / period;
// حساب الانحراف المعياري
const squaredDifferences = slice.map(price => Math.pow(price - sma, 2));
const variance = squaredDifferences.reduce((sum, val) => sum + val, 0) / period;
const standardDeviation = Math.sqrt(variance);
// حساب النطاقات العليا والسفلى
const upperBand = sma + (standardDeviation * stdDev);
const lowerBand = sma - (standardDeviation * stdDev);
result.push({
price: prices[i],
middle: sma,
upper: upperBand,
lower: lowerBand
});
}
}
return result;
};
const predictNextPrice = (priceData) => {
// استخدام آخر 5 أيام للتنبؤ
const recentPrices = priceData.slice(-5).map(item => item.price);
// حساب متوسط التغير
let changes = [];
for (let i = 1; i < recentPrices.length; i++) {
changes.push(recentPrices[i] - recentPrices[i-1]);
}
const avgChange = changes.reduce((a, b) => a + b, 0) / changes.length;
// آخر سعر + متوسط التغير
const predictedPrice = recentPrices[recentPrices.length - 1] + avgChange;
// الاتجاه العام
const trend = avgChange > 0 ? 'صاعد' : avgChange < 0 ? 'هابط' : 'محايد';
// آخر حالة بولينجر
const lastBollinger = bollingerData[bollingerData.length - 1];
let signal = 'محايد';
if (lastBollinger) {
const lastPrice = lastBollinger.price;
// إذا كان السعر فوق النطاق العلوي، فهناك احتمال بيع
if (lastPrice > lastBollinger.upper) {
signal = 'احتمال بيع';
}
// إذا كان السعر تحت النطاق السفلي، فهناك احتمال شراء
else if (lastPrice < lastBollinger.lower) {
signal = 'احتمال شراء';
}
}
return {
predictedPrice: predictedPrice.toFixed(2),
trend,
signal
};
};
const analyzeBollingerBands = async () => {
if (!file) {
setStatus('الرجاء اختيار ملف CSV أولاً');
return;
}
setIsAnalyzing(true);
setStatus('جاري تحليل البيانات...');
setShowResults(false);
try {
const fileContent = await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.readAsText(file);
});
Papa.parse(fileContent, {
header: true,
skipEmptyLines: true,
dynamicTyping: true,
complete: (results) => {
if (results.data && results.data.length > 0) {
// محاولة العثور على عمود السعر
const firstRow = results.data[0];
let priceColumn = '';
// البحث عن اسم العمود المحتمل الذي يمثل سعر الإغلاق
const possibleColumns = ['إغلاق', 'Close', 'close', 'سعر الإغلاق', 'الإغلاق', 'Price', 'price', 'السعر'];
for (const col of possibleColumns) {
if (firstRow[col] !== undefined) {
priceColumn = col;
break;
}
}
if (!priceColumn) {
// إذا لم يتم العثور على عمود محدد، استخدم أول عمود رقمي
for (const key in firstRow) {
if (typeof firstRow[key] === 'number') {
priceColumn = key;
break;
}
}
}
if (!priceColumn) {
setStatus('لم يتم العثور على بيانات السعر في الملف');
setIsAnalyzing(false);
return;
}
// استخراج بيانات السعر والتاريخ
const dateColumn = Object.keys(firstRow).find(key =>
key.toLowerCase().includes('date') ||
key.toLowerCase().includes('تاريخ') ||
key.toLowerCase().includes('يوم')
) || 'Date';
// ترتيب البيانات حسب التاريخ - من الأقدم إلى الأحدث
const sortedData = [...results.data];
if (dateColumn in sortedData[0]) {
sortedData.sort((a, b) => {
if (typeof a[dateColumn] === 'string' && typeof b[dateColumn] === 'string') {
return new Date(a[dateColumn]) - new Date(b[dateColumn]);
}
return 0;
});
}
// استخراج أسعار الإغلاق
const prices = sortedData.map(row => parseFloat(row[priceColumn])).filter(price => !isNaN(price));
// حساب مؤشر البولينجر باند
const bollingerResult = calculateBollingerBands(prices);
// إضافة التاريخ إلى النتائج
const formattedData = sortedData.map((row, index) => ({
date: row[dateColumn] || `Day ${index + 1}`,
price: parseFloat(row[priceColumn]),
...(index < bollingerResult.length ? {
middle: bollingerResult[index].middle,
upper: bollingerResult[index].upper,
lower: bollingerResult[index].lower
} : {})
}));
setData(formattedData);
setBollingerData(bollingerResult);
// التنبؤ بالسعر القادم
const predictionResult = predictNextPrice(formattedData);
setPrediction(predictionResult);
setStatus('تم الانتهاء من التحليل');
setShowResults(true);
} else {
setStatus('لم يتم العثور على بيانات في الملف');
}
setIsAnalyzing(false);
},
error: (error) => {
setStatus('حدث خطأ أثناء قراءة الملف: ' + error.message);
setIsAnalyzing(false);
}
});
} catch (error) {
setStatus('حدث خطأ: ' + error.message);
setIsAnalyzing(false);
}
};
return (
{status && (
{showResults && (
)}
)}
);
};
export default BollingerBandsAnalyzer;
محلل البولينجر باند (Bollinger Bands)
{status}
)}
نتائج التحليل
{prediction && (توقعات الجلسة الحالية:
- السعر المتوقع: {prediction.predictedPrice}
- الاتجاه: {prediction.trend}
- الإشارة: {prediction.signal}
رسم بياني للبولينجر باند:
تحليل الحالة الراهنة:
{bollingerData.length > 0 && (
{(() => {
const lastData = bollingerData[bollingerData.length - 1];
if (!lastData || !lastData.middle) return
)}
لا توجد بيانات كافية للتحليل.
; const lastPrice = lastData.price; let analysis = []; // مقارنة السعر مع المتوسط المتحرك if (lastPrice > lastData.middle) { analysis.push("السعر فوق المتوسط المتحرك، مما يشير إلى اتجاه صاعد محتمل."); } else if (lastPrice < lastData.middle) { analysis.push("السعر تحت المتوسط المتحرك، مما يشير إلى اتجاه هابط محتمل."); } else { analysis.push("السعر قريب من المتوسط المتحرك، مما يشير إلى حالة تذبذب."); } // تحليل موقع السعر من نطاقات البولينجر if (lastPrice > lastData.upper) { analysis.push("السعر فوق النطاق العلوي للبولينجر باند، مما قد يشير إلى حالة تشبع شرائي وإمكانية حدوث ارتداد هبوطي."); } else if (lastPrice < lastData.lower) { analysis.push("السعر تحت النطاق السفلي للبولينجر باند، مما قد يشير إلى حالة تشبع بيعي وإمكانية حدوث ارتداد صعودي."); } else { // تحليل موقع السعر ضمن النطاقات const position = (lastPrice - lastData.lower) / (lastData.upper - lastData.lower); if (position > 0.66) { analysis.push("السعر في الثلث العلوي من نطاق البولينجر، مما يشير إلى قوة نسبية في الاتجاه الصعودي."); } else if (position < 0.33) { analysis.push("السعر في الثلث السفلي من نطاق البولينجر، مما يشير إلى قوة نسبية في الاتجاه الهبوطي."); } else { analysis.push("السعر في منتصف نطاق البولينجر، مما يشير إلى حالة توازن بين العرض والطلب."); } } // تحليل عرض النطاق const width = ((lastData.upper - lastData.lower) / lastData.middle) * 100; if (width > 4) { analysis.push("نطاق البولينجر واسع، مما يشير إلى تقلبات عالية في السوق."); } else if (width < 2) { analysis.push("نطاق البولينجر ضيق، مما قد يشير إلى اقتراب حركة سعرية قوية."); } else { analysis.push("عرض نطاق البولينجر متوسط، مما يشير إلى تقلبات معتدلة في السوق."); } return (-
{analysis.map((item, index) => (
- {item} ))}
ملاحظة: هذا التحليل للأغراض التعليمية فقط وليس توصية استثمارية. يرجى استشارة مستشار مالي قبل اتخاذ أي قرار استثماري.