سورس ربات تلگرام قیمت ارز با Node.js؛ آموزش ساخت ربات اعلام قیمت دلار و سکه
سورس ربات تلگرام قیمت ارز با Node.js: ساخت ربات در BotFather، دستورات /usd و /gold، ارسال خودکار در کانال، کش نرخها، فرمت فارسی و اجرای دائمی با PM2.

- ربات را در BotFather بسازید، توکن را در متغیر محیطی بگذارید و با کتابخانهٔ grammY یا fetch خالص پیام بفرستید.
- نرخها را هر ۶۰ ثانیه از API بگیرید و در حافظه نگه دارید؛ پاسخ به هر پیام کاربر از همین حافظه است.
- برای ارسال در کانال، ربات را ادمین کانال کنید و با setInterval یا cron پیام را ویرایش یا ارسال کنید.
ربات تلگرامی که با دستور /usd قیمت دلار را بگوید یا هر ساعت نرخها را در کانال بگذارد، یکی از محبوبترین پروژههای برنامهنویسهای ایرانی است. در این آموزش سورس ربات تلگرام قیمت ارز را با Node.js قدمبهقدم مینویسیم؛ کد نهایی کامل و قابل اجراست.
npm i grammy کتابخانه را نصب کنید، نرخها را هر ۶۰ ثانیه از https://api.ezrate.me/v1/rates در یک متغیر نگه دارید و در bot.command("usd", …) از همان متغیر جواب بدهید. ربات را با PM2 دائمی اجرا کنید.مفاهیم پایهٔ API در راهنمای کامل API قیمت ارز و طلا آمده است.
گام ۱: ساخت ربات در BotFather
- در تلگرام @BotFather را باز کنید و
/newbotرا بفرستید. - یک نام نمایشی و یک نام کاربری که به
botختم شود انتخاب کنید. - توکنی که BotFather میدهد مثل رمز عبور است؛ آن را جایی منتشر نکنید.
- با
/setcommandsدستورها را تعریف کنید تا در منوی ربات دیده شوند:usd - قیمت دلار،gold - قیمت طلا و سکه.

گام ۲: آمادهسازی پروژه
mkdir price-bot && cd price-bot
npm init -y
npm i grammy
# متغیرها (در سرور در فایل .env یا تنظیمات PM2):
export BOT_TOKEN="123456:ABC…"
export EZRATE_KEY="ezr_live_…"از Node.js نسخهٔ ۱۸ به بعد استفاده کنید تا fetch داخلی در دسترس باشد. در package.json مقدار "type": "module" را اضافه کنید.
گام ۳: کد کامل ربات
// bot.mjs
import { Bot } from "grammy"
const API = "https://api.ezrate.me/v1"
const bot = new Bot(process.env.BOT_TOKEN)
const fa = new Intl.NumberFormat("fa-IR")
let rates = {} // آخرین نرخهای معتبر
let asOf = null
async function refresh() {
try {
const r = await fetch(`${API}/rates?symbols=usd,eur,aed,usdt,g18,mesghal,emami,bahar&lang=fa`, {
headers: { "X-API-Key": process.env.EZRATE_KEY },
signal: AbortSignal.timeout(8000),
})
if (!r.ok) throw new Error(`HTTP ${r.status}`)
const j = await r.json()
rates = Object.fromEntries(j.data.map(x => [x.symbol, x]))
asOf = new Date(j.meta.as_of)
} catch (e) {
console.error("refresh failed:", e.message) // نرخ قبلی میماند
}
}
const line = s => {
const x = rates[s]
if (!x) return ""
const arrow = x.change_pct >= 0 ? "🟢" : "🔴"
return `${arrow} ${x.name}: ${fa.format(x.sell)} تومان`
}
const footer = () => asOf ? `\n🕒 ${asOf.toLocaleTimeString("fa-IR", { timeZone: "Asia/Tehran" })}` : ""
bot.command("start", ctx => ctx.reply("سلام! برای قیمت دلار /usd و برای طلا و سکه /gold را بفرستید."))
bot.command("usd", ctx => ctx.reply([line("usd"), line("eur"), line("aed"), line("usdt")].join("\n") + footer()))
bot.command("gold", ctx => ctx.reply([line("g18"), line("mesghal"), line("emami"), line("bahar")].join("\n") + footer()))
await refresh()
setInterval(refresh, 60_000)
bot.start()نکتهٔ مهم این معماری: ربات به ازای هر پیام کاربر به API درخواست نمیفرستد. نرخها هر دقیقه یکبار گرفته میشوند و همهٔ کاربران از حافظه جواب میگیرند. اگر ربات شما ده هزار کاربر هم داشته باشد، مصرف API همان ۱۴۴۰ درخواست در روز است.
گام ۴: ارسال خودکار در کانال
ربات را به کانال اضافه و ادمین کنید (فقط با دسترسی ارسال پیام). سپس با یک زمانبند ساده پیام بفرستید. برای جلوگیری از شلوغی کانال، بهجای پیام جدید میتوانید یک پیام ثابت را ویرایش کنید:
const CHANNEL = "@your_channel"
let messageId = null
async function postToChannel() {
const text = ["📊 نرخ لحظهای بازار", line("usd"), line("eur"), line("g18"), line("emami")].join("\n") + footer()
if (messageId) {
await bot.api.editMessageText(CHANNEL, messageId, text).catch(() => {})
} else {
messageId = (await bot.api.sendMessage(CHANNEL, text)).message_id
}
}
setInterval(postToChannel, 10 * 60_000) // هر ۱۰ دقیقهگام ۵: اجرای دائمی روی سرور
npm i -g pm2
pm2 start bot.mjs --name price-bot
pm2 save && pm2 startup # اجرای خودکار بعد از ریاستارت سرورسرور باید به api.telegram.org دسترسی داشته باشد. اگر سرور شما در ایران است و این دسترسی ندارد، ربات را روی یک سرور خارج از کشور اجرا کنید؛ API نرخها از هر دو مسیر در دسترس است.
ایدههایی برای توسعه
- دستور
/convert 100 usdبا مسیرconvertAPI. - هشدار شخصی: کاربر عدد هدف را ثبت کند و وقتی دلار به آن رسید پیام بگیرد.
- نمودار: تصویر نمودار روزانه را از دادهٔ
historyبسازید و باsendPhotoبفرستید. - زمانبندی در ساعت کاری؛ ایدههای آن در زمانبندی ارسال قیمت در کانال تلگرام آمده است.
ساختار پیام خوب در کانال قیمت
تفاوت یک کانال قیمت حرفهای با بقیه در جزئیات پیام است. پیامهای پرخواننده معمولاً این ویژگیها را دارند:
- ترتیب ثابت: دلار، یورو، درهم، تتر، طلا و سکه همیشه به یک ترتیب؛ خواننده عادت میکند سریع پیدا کند.
- جهت تغییر: یک نشانهٔ رنگی (🟢 / 🔴) کنار هر نرخ، بدون شلوغ کردن پیام با درصدهای اعشاری زیاد.
- زمان: ساعت به وقت تهران پایین پیام؛ پیام بیزمان در کانال قیمت بیاعتبار است.
- منبع: نام و لینک منبع نرخ؛ هم شرط استفاده است و هم اعتماد میسازد.
- کوتاهی: پیامی که در پیشنمایش اعلان تلگرام کامل دیده شود، بیشتر خوانده میشود.
امنیت توکن ربات
هر کس توکن ربات شما را داشته باشد، میتواند به نام ربات در کانال پیام بگذارد. توکن را فقط در متغیر محیطی سرور نگه دارید، در لاگها چاپ نکنید و اگر احتمال لو رفتن دادید، از BotFather با دستور /revoke توکن جدید بگیرید. ربات را فقط با حداقل دسترسی (ارسال و ویرایش پیام) ادمین کانال کنید، نه با اختیار حذف اعضا یا تغییر اطلاعات کانال.
Long Polling یا Webhook؟
کد بالا با bot.start() از Long Polling استفاده میکند: ربات خودش مرتب از تلگرام میپرسد پیام جدید هست یا نه. این روش برای شروع سادهترین است و به دامنه و SSL نیاز ندارد. وقتی ربات بزرگ شد یا روی سرورلس (مثل Cloudflare Workers) اجرا شد، Webhook بهتر است: تلگرام پیامها را خودش به آدرس HTTPS شما میفرستد. منطق دریافت نرخ در هر دو یکی است.
ذخیرهٔ کاربران و ارسال به زبان آنها
اگر ربات شما کاربران خارج از ایران هم دارد، lang=en در درخواست نام داراییها را انگلیسی برمیگرداند. زبان هر کاربر را از ctx.from.language_code بخوانید و دو نسخه از نرخها (فارسی و انگلیسی) را در حافظه نگه دارید؛ باز هم فقط دو درخواست در دقیقه.

نرخهای لحظهای مرتبط با این مطلب: قیمت دلار، قیمت طلای ۱۸ عیار، قیمت سکه امامی.

نظرات (۰)
نظرها پس از تأیید نمایش داده میشوند؛ برای ارسال، ورود به حساب لازم است.


