|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Crypto Trading Advisor</title> |
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
</head> |
|
<body class="bg-gray-100 text-gray-800 font-sans"> |
|
|
|
<div class="container mx-auto p-4"> |
|
|
|
<h1 class="text-3xl font-bold text-center mb-6">Crypto Trading Advisor</h1> |
|
|
|
|
|
<div class="flex justify-center mb-4 flex-wrap"> |
|
<select id="crypto-select" class="p-2 border border-gray-300 rounded-md shadow-md w-full sm:w-auto"> |
|
<option value="">Загрузка криптовалют...</option> |
|
</select> |
|
<button id="get-advice" class="ml-4 px-4 py-2 bg-blue-500 text-white rounded-md shadow-md hover:bg-blue-600 w-full sm:w-auto"> |
|
Получить совет |
|
</button> |
|
</div> |
|
|
|
|
|
<div id="result" class="bg-white p-6 rounded-md shadow-md"> |
|
<p class="text-center text-gray-500">Выберите криптовалюту, чтобы увидеть советы, графики и новости.</p> |
|
</div> |
|
|
|
|
|
<div class="mt-6"> |
|
<canvas id="crypto-chart" class="bg-white p-4 rounded-md shadow-md"></canvas> |
|
</div> |
|
|
|
|
|
<div id="news-section" class="mt-6 bg-white p-6 rounded-md shadow-md"> |
|
<h2 class="text-xl font-bold mb-4">Новости</h2> |
|
<ul id="news-list" class="list-disc pl-5"> |
|
<li class="text-gray-500">Здесь появятся новости о криптовалютах.</li> |
|
</ul> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
const API_BASE = 'https://api.coingecko.com/api/v3'; |
|
const NEWS_API_KEY = 'your_newsapi_key_here'; |
|
const NEWS_API_URL = 'https://newsapi.org/v2/everything'; |
|
const resultDiv = document.getElementById('result'); |
|
const select = document.getElementById('crypto-select'); |
|
const button = document.getElementById('get-advice'); |
|
const chartCanvas = document.getElementById('crypto-chart'); |
|
const newsList = document.getElementById('news-list'); |
|
let chartInstance; |
|
|
|
|
|
async function loadCryptos() { |
|
try { |
|
const response = await fetch(`${API_BASE}/coins/list`); |
|
const data = await response.json(); |
|
select.innerHTML = data |
|
.slice(0, 50) |
|
.map(coin => `<option value="${coin.id}">${coin.name} (${coin.symbol.toUpperCase()})</option>`) |
|
.join(''); |
|
} catch (error) { |
|
console.error('Ошибка при загрузке списка криптовалют:', error); |
|
select.innerHTML = '<option>Ошибка загрузки...</option>'; |
|
} |
|
} |
|
|
|
|
|
async function fetchCryptoData(crypto) { |
|
try { |
|
const response = await fetch(`${API_BASE}/coins/${crypto}/market_chart?vs_currency=usd&days=30`); |
|
const data = await response.json(); |
|
return data; |
|
} catch (error) { |
|
console.error('Ошибка при загрузке данных о криптовалюте:', error); |
|
resultDiv.innerHTML = `<p class="text-red-500">Ошибка при загрузке данных. Попробуйте позже.</p>`; |
|
} |
|
} |
|
|
|
|
|
async function fetchNews(query) { |
|
try { |
|
const response = await fetch(`${NEWS_API_URL}?q=${query}&apiKey=${NEWS_API_KEY}`); |
|
const data = await response.json(); |
|
return data.articles; |
|
} catch (error) { |
|
console.error('Ошибка при загрузке новостей:', error); |
|
newsList.innerHTML = `<li class="text-red-500">Ошибка при загрузке новостей.</li>`; |
|
} |
|
} |
|
|
|
|
|
function renderChart(prices, volumes, predictions = []) { |
|
const labels = prices.map((_, index) => `Day ${index + 1}`); |
|
const priceData = prices.map(price => price[1]); |
|
const volumeData = volumes.map(volume => volume[1]); |
|
|
|
if (chartInstance) { |
|
chartInstance.destroy(); |
|
} |
|
|
|
chartInstance = new Chart(chartCanvas, { |
|
type: 'line', |
|
data: { |
|
labels: labels, |
|
datasets: [ |
|
{ |
|
label: 'Цена (USD)', |
|
data: priceData, |
|
backgroundColor: 'rgba(59, 130, 246, 0.2)', |
|
borderColor: 'rgba(59, 130, 246, 1)', |
|
borderWidth: 2, |
|
fill: true, |
|
}, |
|
{ |
|
label: 'Объем торгов (USD)', |
|
data: volumeData, |
|
backgroundColor: 'rgba(34, 197, 94, 0.2)', |
|
borderColor: 'rgba(34, 197, 94, 1)', |
|
borderWidth: 2, |
|
fill: true, |
|
}, |
|
{ |
|
label: 'Прогноз цены', |
|
data: predictions, |
|
borderColor: 'rgba(255, 99, 132, 1)', |
|
borderWidth: 2, |
|
borderDash: [5, 5], |
|
fill: false, |
|
}, |
|
], |
|
}, |
|
options: { |
|
responsive: true, |
|
plugins: { |
|
legend: { |
|
display: true, |
|
}, |
|
}, |
|
}, |
|
}); |
|
} |
|
|
|
|
|
async function analyzeWithLSTM(prices, callback) { |
|
const data = prices.map(price => price[1]); |
|
const normalizedData = data.map(value => value / Math.max(...data)); |
|
|
|
const inputs = tf.tensor(normalizedData.slice(0, -1)); |
|
const targets = tf.tensor(normalizedData.slice(1)); |
|
|
|
const model = tf.sequential(); |
|
model.add(tf.layers.lstm({ units: 50, inputShape: [1, 1], returnSequences: false })); |
|
model.add(tf.layers.dense({ units: 1 })); |
|
|
|
model.compile({ optimizer: 'adam', loss: 'meanSquaredError' }); |
|
|
|
const inputReshaped = inputs.reshape([inputs.size, 1, 1]); |
|
const targetReshaped = targets.reshape([targets.size, 1]); |
|
|
|
const predictions = []; |
|
|
|
|
|
await model.fit(inputReshaped, targetReshaped, { |
|
epochs: 50, |
|
callbacks: { |
|
onEpochEnd: (epoch, logs) => { |
|
const prediction = model.predict(inputReshaped); |
|
const predData = prediction.dataSync(); |
|
predictions.length = 0; |
|
predictions.push(...predData.map(v => v * Math.max(...data))); |
|
callback(predictions); |
|
}, |
|
}, |
|
}); |
|
|
|
return predictions; |
|
} |
|
|
|
|
|
button.addEventListener('click', async () => { |
|
const crypto = select.value; |
|
if (!crypto) { |
|
resultDiv.innerHTML = `<p class="text-red-500">Выберите криптовалюту.</p>`; |
|
return; |
|
} |
|
|
|
resultDiv.innerHTML = '<p class="text-gray-500">Загрузка данных...</p>'; |
|
const data = await fetchCryptoData(crypto); |
|
|
|
if (data) { |
|
const { prices, total_volumes } = data; |
|
|
|
const predictions = await analyzeWithLSTM(prices, (updatedPredictions) => { |
|
renderChart(prices, total_volumes, updatedPredictions); |
|
}); |
|
|
|
renderChart(prices, total_volumes, predictions); |
|
|
|
const news = await fetchNews(crypto); |
|
newsList.innerHTML = news |
|
.slice(0, 5) |
|
.map(article => `<li><a href="${article.url}" target="_blank" class="text-blue-500">${article.title}</a></li>`) |
|
.join(''); |
|
} |
|
}); |
|
|
|
|
|
loadCryptos(); |
|
</script> |
|
</body> |
|
</html> |