227 lines
8.4 KiB
JavaScript
227 lines
8.4 KiB
JavaScript
const { Bot } = require("grammy");
|
||
|
||
// Токен из .env (не хардкодить!)
|
||
const bot = new Bot(process.env.BOT_TOKEN || "7891234567:AAF_z8kN3xQ5vR9mP2wL7tY4uH6jK1sD0cB");
|
||
|
||
// === БАЗА ДАННЫХ ПОЛЬЗОВАТЕЛЕЙ ===
|
||
let users = new Set();
|
||
|
||
// === СИГНАЛЫ И НОВОСТИ ===
|
||
const signals = [
|
||
{ pair: 'EUR/USD', dir: '📈', type: 'Покупка', entry: 1.0850, sl: 1.0830, tp: 1.0890, time: '10:45' },
|
||
{ pair: 'GBP/USD', dir: '📉', type: 'Продажа', entry: 1.2680, sl: 1.2710, tp: 1.2620, time: '10:30' },
|
||
{ pair: 'XAU/USD', dir: '📈', type: 'Покупка', entry: 2035, sl: 2025, tp: 2055, time: '09:50' },
|
||
{ pair: 'BTC/USD', dir: '📉', type: 'Продажа', entry: 42500, sl: 43200, tp: 41100, time: '09:20' }
|
||
];
|
||
|
||
const news = [
|
||
{ title: '🔴 Решение по ставке ФРС (США)', time: '14:00', impact: 'Важно' },
|
||
{ title: '🔴 Инфляция CPI (Еврозона)', time: '12:00', impact: 'Важно' },
|
||
{ title: '🟡 ВВП Великобритании', time: '09:30', impact: 'Средне' },
|
||
{ title: '🟢 Розничные продажи (Япония)', time: '08:30', impact: 'Слабо' }
|
||
];
|
||
|
||
const candles = [
|
||
{ name: '🔨 Молот (Hammer)', type: 'Бычий разворот', desc: 'Появляется после нисходящего тренда. Длинная нижняя тень.' },
|
||
{ name: '☄️ Падающая звезда', type: 'Медвежий разворот', desc: 'Длинная верхняя тень, отскок от сопротивления.' },
|
||
{ name: '📈 Бычье поглощение', type: 'Бычий разворот', desc: 'Зелёная свеча перекрывает предыдущую красную.' },
|
||
{ name: '📉 Медвежье поглощение', type: 'Медвежий разворот', desc: 'Красная свеча перекрывает предыдущую зелёную.' },
|
||
{ name: '➕ Доджи (Doji)', type: 'Неопределённость', desc: 'Цена открытия = цена закрытия.' },
|
||
{ name: '🌅 Утренняя звезда', type: 'Бычий разворот', desc: '3 свечи: красная, маленькая, зелёная.' },
|
||
{ name: '🌆 Вечерняя звезда', type: 'Медвежий разворот', desc: '3 свечи: зелёная, маленькая, красная.' }
|
||
];
|
||
|
||
// === КОМАНДЫ ===
|
||
bot.command("start", async (ctx) => {
|
||
users.add(ctx.from.id);
|
||
await ctx.reply(
|
||
`👋 Привет, ${ctx.from.first_name}!
|
||
|
||
📊 *Forex Assistant Bot* — твой помощник в торговле
|
||
|
||
💰 Стартовый капитал: $100
|
||
📈 Графики, сигналы, новости, свечи
|
||
|
||
*Команды:*
|
||
/signals — текущие сигналы
|
||
/news — важные новости
|
||
/candles — справочник свечей
|
||
/risk — калькулятор риска
|
||
/help — помощь
|
||
|
||
⚠️ Это обучающий бот. Реальные деньги — только через брокера.`,
|
||
{ parse_mode: "Markdown" }
|
||
);
|
||
});
|
||
|
||
bot.command("help", async (ctx) => {
|
||
await ctx.reply(
|
||
`📚 *Помощь*
|
||
|
||
*Сигналы* — готовые идеи для сделок с точками входа, стоп-лосс и тейк-профит.
|
||
|
||
*Новости* — экономические события, влияющие на рынок (инфляция, ВВП, ставки).
|
||
|
||
*Свечи* — 12 основных паттернов для анализа графика.
|
||
|
||
*Риск* — расчёт лота для депозита $100 (риск 1-2% на сделку).
|
||
|
||
🌐 *Веб-версия:*
|
||
Открой дашборд в браузере: https://pages.git.vibe42.kz/Erlan/pomoschnik-po-torgam-na-fore/
|
||
|
||
⚠️ *Дисклеймер:*
|
||
Это не финансовая рекомендация. Торговля на форекс — высокий риск.`,
|
||
{ parse_mode: "Markdown" }
|
||
);
|
||
});
|
||
|
||
bot.command("signals", async (ctx) => {
|
||
const text = signals.map(s =>
|
||
`*${s.dir} ${s.pair}* — ${s.type}
|
||
Вход: ${s.entry}
|
||
Стоп: ${s.sl} | Тейк: ${s.tp}
|
||
Время: ${s.time}`
|
||
).join('\n\n');
|
||
|
||
await ctx.reply(
|
||
`🎯 *Торговые сигналы*\n\n${text}`,
|
||
{ parse_mode: "Markdown" }
|
||
);
|
||
});
|
||
|
||
bot.command("news", async (ctx) => {
|
||
const text = news.map(n =>
|
||
`${n.title}\n⏰ ${n.time} • ${n.impact}`
|
||
).join('\n\n');
|
||
|
||
await ctx.reply(
|
||
`📰 *Новости рынка*\n\n${text}`,
|
||
{ parse_mode: "Markdown" }
|
||
);
|
||
});
|
||
|
||
bot.command("candles", async (ctx) => {
|
||
const keyboard = {
|
||
reply_markup: {
|
||
inline_keyboard: candles.map(c => [
|
||
{ text: c.name.split(' ')[0] + ' ' + c.name.split(' ')[1], callback_data: `candle_${candles.indexOf(c)}` }
|
||
])
|
||
}
|
||
};
|
||
|
||
await ctx.reply(
|
||
'🕯️ *Свечные паттерны*\n\nВыберите паттерн:',
|
||
{ parse_mode: "Markdown", ...keyboard }
|
||
);
|
||
});
|
||
|
||
bot.command("risk", async (ctx) => {
|
||
await ctx.reply(
|
||
`🧮 *Калькулятор риска*
|
||
|
||
*Правила:*
|
||
• Риск на сделку: 1-2% депозита
|
||
• Стоп-лосс ОБЯЗАТЕЛЕН
|
||
• Соотношение риск/прибыль: минимум 1:2
|
||
|
||
*Пример для $100:*
|
||
Риск 2% = $2 на сделку
|
||
Стоп-лосс 20 пунктов
|
||
Лот = 0.01 (мини-лот)
|
||
Тейк-профит = 40 пунктов
|
||
Прибыль = $4
|
||
|
||
🌐 Полный калькулятор в веб-версии:
|
||
https://pages.git.vibe42.kz/Erlan/pomoschnik-po-torgam-na-fore/`,
|
||
{ parse_mode: "Markdown" }
|
||
);
|
||
});
|
||
|
||
bot.command("broadcast", async (ctx) => {
|
||
// Рассылка всем пользователям (только для админа)
|
||
if (ctx.from.id !== 123456789) {
|
||
return ctx.reply('❌ Нет доступа');
|
||
}
|
||
|
||
const message = ctx.message.text.replace('/broadcast ', '');
|
||
let count = 0;
|
||
|
||
for (const userId of users) {
|
||
try {
|
||
await bot.api.sendMessage(userId, message, { parse_mode: "Markdown" });
|
||
count++;
|
||
} catch (e) {
|
||
console.log(`Не удалось отправить ${userId}`);
|
||
}
|
||
}
|
||
|
||
await ctx.reply(`✅ Отправлено ${count} пользователям`);
|
||
});
|
||
|
||
// === ОБРАБОТКА КНОПОК ===
|
||
bot.on("callback_query:data", async (ctx) => {
|
||
const data = ctx.callbackQuery.data;
|
||
|
||
if (data.startsWith('candle_')) {
|
||
const index = parseInt(data.split('_')[1]);
|
||
const candle = candles[index];
|
||
|
||
await ctx.answerCallbackQuery();
|
||
await ctx.reply(
|
||
`*${candle.name}*\n\nТип: ${candle.type}\n\n${candle.desc}`,
|
||
{ parse_mode: "Markdown" }
|
||
);
|
||
}
|
||
});
|
||
|
||
// === ОБРАБОТКА ТЕКСТА ===
|
||
bot.on("message:text", async (ctx) => {
|
||
const text = ctx.message.text.toLowerCase();
|
||
|
||
if (text.includes('привет') || text.includes('здравствуй')) {
|
||
await ctx.reply(`👋 Привет, ${ctx.from.first_name}! Чем могу помочь?`);
|
||
}
|
||
|
||
if (text.includes('свеч') || text.includes('паттерн')) {
|
||
await ctx.reply('🕯️ Используй команду /candles для справочника свечей.');
|
||
}
|
||
|
||
if (text.includes('новост') || text.includes('событи')) {
|
||
await ctx.reply('📰 Используй команду /news для последних новостей.');
|
||
}
|
||
|
||
if (text.includes('сигнал') || text.includes('сделк')) {
|
||
await ctx.reply('🎯 Используй команду /signals для текущих сигналов.');
|
||
}
|
||
});
|
||
|
||
// === ЗАПУСК ===
|
||
bot.start().catch((err) => {
|
||
console.error("Ошибка запуска бота:", err);
|
||
});
|
||
|
||
console.log("🤖 Forex Bot запущен...");
|
||
|
||
// === РАССЫЛКА СИГНАЛОВ КАЖДЫЕ 4 ЧАСА ===
|
||
setInterval(async () => {
|
||
if (users.size === 0) return;
|
||
|
||
const signal = signals[Math.floor(Math.random() * signals.length)];
|
||
const message = `🎯 *Новый сигнал!*
|
||
|
||
${signal.dir} *${signal.pair}* — ${signal.type}
|
||
Вход: ${signal.entry}
|
||
Стоп: ${signal.sl}
|
||
Тейк: ${signal.tp}
|
||
|
||
⚠️ Это учебный сигнал. Реальные деньги — через брокера.`;
|
||
|
||
for (const userId of users) {
|
||
try {
|
||
await bot.api.sendMessage(userId, message, { parse_mode: "Markdown" });
|
||
} catch (e) {
|
||
console.log(`Не удалось отправить ${userId}`);
|
||
}
|
||
}
|
||
}, 4 * 60 * 60 * 1000); // 4 часа
|