בחירת שרת VPS לבוט מסחר: מה באמת חשוב?
מדריך טכני לבחירת VPS עבור בוט מסחר. נסביר מדוע יציבות תלויה בהגדרות systemd ולא בנתוני השרת, איך למנוע crash-loop עם StartLimitBurst ומהם הפרמטרים הקריטיים לתפעול שוטף.
מה בוט מסחר צריך משרת VPS
שרת VPS עבור בוטים למסחר נמדד לפי ארבעה קריטריונים: האם התהליך מתאושש לאחר קריסה, האם השעון מכוון, האם קשה לגנוב את מפתחות ה-API (ממשק תכנות יישומים), והאם מתקבלת התראה כשהוא מפסיק לעבוד. מהירות גולמית נמצאת נמוך ברשימה זו עבור בוט קמעונאי, כיוון שהחלק האיטי בנתיב הפקודה שלכם הוא הברוקר והמרחק אליו, ולא המארח שמריץ את ה-Python שלכם.
זהו מדריך הנדסי. אין כאן ייעוץ פיננסי, ולא נדון באף אסטרטגיה.
זמינות היא משמעת של אתחול, לא מספר בדף מכירות
כל מארח בעולם מפרסם זמינות של 99.9 אחוזים. הנתון הזה מתאר את ה-hypervisor, לא את ה-bot שלכם. ה-bot קורס בגלל חריגה שלא טופלה, WebSocket שלעולם לא מתחבר מחדש, או ה-OOM (out of memory) killer, בעוד השרת נשאר פעיל כל הזמן. לכן, השאלה המועילה היא מה קורה בעשר השניות שאחרי יציאת התהליך שלכם.
הריצו את ה-bot כשירות systemd ואפשרו למערכת ה-init לנהל את האתחול מחדש. קובץ unit עושה זאת בשישה שורות.
[Unit]
Description=Trading bot
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
Type=simple
User=bot
WorkingDirectory=/opt/tradingbot
EnvironmentFile=/etc/tradingbot/api.env
ExecStart=/opt/tradingbot/venv/bin/python -m tradingbot
Restart=always
RestartSec=10
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/tradingbot
[Install]
WantedBy=multi-user.targetStartLimitIntervalSec=0 היא השורה שאנשים מפספסים. כברירת מחדל, systemd מוותר לאחר 5 אתחולים בתוך 10 שניות ומשאיר את ה-unit במצב failed לנצח, וזה בדיוק ההתנהגות שאינכם רוצים בשעה 03:00. הגדרת הערך ל-0 מבטלת את מגבלת הקצב, כך ש-bot שנמצא ב-crash-loop ימשיך לנסות במקום להשתתק. RestartSec=10 עוצר את הלולאה הזו מלהציף את ה-exchange בבקשות התחברות מחדש.
בדקו את הקובץ לפני שאתם סומכים עליו, ולאחר מכן הפעילו אותו:
sudo systemd-analyze verify /etc/systemd/system/tradingbot.service
sudo systemctl daemon-reload
sudo systemctl enable --now tradingbot
systemctl status tradingbotenable הוא החצי ששורד reboot, ועדכוני kernel משמעותם reboot. כדי לראות אם ה-bot גווע בשקט, בקשו מ-systemd את מונה האתחולים:
systemctl show tradingbot -p NRestarts
journalctl -u tradingbot --since "24 hours ago" | tail -50NRestarts=0 אחרי שבוע מעיד על bot תקין. NRestarts=812 אומר שסחרתם על תהליך שמתחבר מחדש כל הלילה. האנטומיה המלאה של קובץ ה-unit, כולל טיימרים למשימות מתוזמנות כמו דוח יומי, מכוסה ב-הרצת תוכנית כשירות systemd.
הגדרת השעון ל-UTC ווידוא סנכרון
ממשקי API של בורסות חותמים על בקשות באמצעות חותמת זמן ודוחים כל בקשה שחורגת מחלון זמן מסוים, לרוב 5 שניות או פחות. שעון שאינו מסונכרן גורם לשגיאות שנראות כמו כשל באימות, מה שמוביל משתמשים להחליף מפתחות במשך שעות לפני שהם בודקים את השעה. בממשקי API בסגנון Binance, ההודעה היא מפורשת: Timestamp for this request was 1000ms ahead of the server's time.
הגדירו את השרת ל-UTC. אזורי זמן מקומיים מציגים שינויי שעון קיץ שעלולים להתרחש באמצע סשן מסחר.
sudo timedatectl set-timezone UTC
timedatectlהפצת Ubuntu כוללת את systemd-timesyncd, שהוא לקוח SNTP (פרוטוקול זמן רשת פשוט). הוא מתאים ללוגים אך חלש עבור כל מה שדורש דיוק של מילי-שניות בודדות, כיוון שהוא מבצע תשאול לשרת אחד ואינו מבצע כיול רציף לשעון. השתמשו ב-chrony במקום:
sudo apt update && sudo apt install -y chrony
sudo systemctl enable --now chrony
chronyc tracking
chronyc sources -vהשורה שיש לקרוא מתוך chronyc tracking היא System time, לדוגמה System time : 0.000031415 seconds fast of NTP time. כל ערך הנמוך ממילי-שניות בודדות הוא תקין. אם מופיע Leap status : Not synchronised, סימן ש-chrony טרם הגיע לשרת, לרוב בגלל חסימה של תעבורת UDP 123 יוצאת. המתינו דקה ובדקו שוב לפני שאתם משנים חוקי firewall.
שמירה על מפתחות API מחוץ למקומות שאתם מעתיקים אליהם
מפתח בורסה (exchange key) שדלף גרוע יותר ממפתח SSH שדלף, כיוון שהרשאת משיכה הופכת אותו לכסף באופן מיידי. שני הרגלים מכסים את רוב הסיכון.
ראשית, לעולם אל תעניקו הרשאת משיכה למפתח של בוט, ובמקומות שבהם הבורסה תומכת בכך, קשרו את המפתח לכתובת ה-IP של השרת שלכם. זהו בקרת האבטחה היחידה שהופכת מפתח גנוב לכמעט חסר תועלת.
שנית, שמרו את ה-secret מחוץ לספריית הקוד. כל דבר שנמצא בתוך /opt/tradingbot יגיע במוקדם או במאוחר למאגר git או לארכיון גיבוי. שמרו אותו בקובץ בבעלות root שרק systemd קורא:
sudo install -d -m 750 -o root -g bot /etc/tradingbot
sudo install -m 640 -o root -g bot /dev/null /etc/tradingbot/api.env
sudo nano /etc/tradingbot/api.envהקובץ מכיל שורות KEY=value פשוטות ללא מרכאות וללא export. מצב 640 עם קבוצת bot אומר שמשתמש השירות יכול לקרוא אותו ואף אחד אחר לא. ודאו זאת עם sudo -u bot cat /etc/tradingbot/api.env ולאחר מכן עם כל משתמש אחר, שם הפעולה חייבת להיכשל עם Permission denied.
הבוט עצמו לא אמור לרוץ כ-root או כמשתמש ההתחברות שלכם. צרו חשבון מערכת ללא shell וללא ספריית בית להתחבר אליה:
sudo useradd --system --shell /usr/sbin/nologin --home-dir /var/lib/tradingbot --create-home botההיגיון מאחורי כל אחד מהדגלים הללו, ועד כמה ProtectSystem=strict באמת מגן, מפורט ב-הרצת שירותים כמשתמש ללא הרשאות. שאר בסיס השרת, מפתחות SSH ו-firewall, שייכים ל-עשר הדקות הראשונות ב-VPS חדש.
גלו שהשירות מושבת לפני שהברוקר שלכם יגלה זאת
systemctl status מדווח שהתהליך רץ. הוא לא מציין אם הבוט אכן מבצע פעולה כלשהי. תהליך שנתקע בלולאת ניסיונות חוזרים מול WebSocket מת יעבור כל בדיקה ש-systemd מסוגל לבצע.
השתמשו ב-heartbeat במקום זאת. ל-Uptime Kuma יש צגי דחיפה (push monitors): הוא מצפה שהבוט שלכם יקרא לכתובת URL לפי לוח זמנים, ומתריע כאשר הקריאה מפסיקה להגיע. מקמו את הקריאה בסוף הלולאה הראשית שלכם, לאחר החלק שמוכיח שהבוט חי, כגון קריאה מוצלחת של נתוני שוק.
curl -fsS "http://monitor.example.com:3001/api/push/YOUR_TOKEN?status=up&msg=loop_ok"הגדירו את מרווח הניטור לכפליים מזמן הלולאה שלכם, כדי ששינויים רגילים בתזמון (jitter) לא יגרמו להקפצת התראות שווא. הריצו את הצג בשרת נפרד מהבוט, שכן צג שקורס יחד עם השירות שהוא מנטר לא ידווח על דבר. ההגדרה מפורטת ב-ניטור סטטוס בהתארחות עצמית עם Uptime Kuma.
הוסיפו גם התראת דיסק. בוט שכותב לוגים מפורטים ימלא את מערכת הקבצים של ה-root בתוך שבועות, ודיסק מלא עוצר את הכתיבה למסד הנתונים, אך לא את הקריאה לרשת, לכן הסימפטומים יהיו מוזרים. journalctl --vacuum-time=14d ושורת SystemMaxUse= בתוך /etc/systemd/journald.conf ישמרו על גודל ה-journal מוגבל.
האמת הכנה: השהיה (latency) היא לרוב לא באשמת השרת שלכם
כאן שוק מוצרי ה-VPS למסחר מפסיק להיות טכני. דפי שיווק מצטטים נתונים של תת-מילי-שניות ורומזים שהשרת הוא הגורם המפריד ביניכם לבין ביצוע פקודה. עבור כמעט כל בוט קמעונאי, זה לא המצב.
הפקודה שלכם עוברת מהבוט אל נקודת הקצה של הבורסה או הברוקר דרך האינטרנט הציבורי. המסלול הזה מוכתב על ידי מרחק פיזי ועל ידי הסכמי ה-peering בין הספק שלכם לספק שלהם. שרת ב-Frankfurt שמתקשר עם נקודת קצה ב-Tokyo משלם בערך 250 מילי-שניות לכל כיוון, ללא קשר למהירות ה-CPU. לאחר מכן, המערכות של הברוקר מוסיפות את התור שלהן, את בדיקות הסיכונים ואת מגבלות ה-rate limit, שבחשבון קמעונאי נמדדות בדרך כלל בעשרות או מאות מילי-שניות.
מדדו זאת במקום לנחש. curl מדווח על זמני החיבור וזמן ה-first-byte עבור נקודת קצה אמיתית:
curl -s -o /dev/null -w 'dns=%{time_namelookup}s connect=%{time_connect}s ttfb=%{time_starttransfer}s\n' \
https://api.kraken.com/0/public/Time
mtr -rwzc 100 api.kraken.comהריצו זאת משרת מועמד לפני שתתחייבו. אם connect הוא 0.180 שניות, אתם ביבשת הלא נכונה, וזה משהו ששווה לתקן. אם connect הוא 0.004 שניות ו-ttfb הוא 0.140 שניות, העיכוב הנותר הוא העיבוד של הברוקר, ושום החלפת שרת לא תשנה זאת.
אז מתי השרת כן משנה? כאשר אתם נמצאים ב-colocation או בחיבור ישיר לבורסה ומתחרים על מיקום בתור, שזה עסק אחר עם תקציב אחר. או כאשר הקוד שלכם הוא צוואר הבקבוק: בוט שמחשב מחדש אינדיקטורים על פני היסטוריה מלאה בכל tick יכול לשרוף 200 מילי-שניות של CPU בכל לולאה; זו השהיה אמיתית שאתם שולטים בה בחינם. בצעו profiling ללולאה לפני שאתם מחפשים שרת מהיר יותר.
מה שכן משנה בשרת שתבחרו הוא מיקום גיאוגרפי, רשת יציבה, ומספיק זיכרון כדי שה-OOM killer לעולם לא יצטרך להתערב. נכון ליולי 2026, בוט Python עם אסטרטגיה בודדת ומאות סמלים בזיכרון רץ בנוחות על 2 GB של RAM ו-2 vCPU. הוסיפו זיכרון אם אתם שומרים היסטוריית tick במסד נתונים מקומי.
רשימת תיוג מקוצרת לפני עלייה לאוויר
systemctl is-enabled tradingbotמדפיסenabled, והשירות שורדsudo reboot.chronyc trackingמדווח על סטיית זמן מערכת של פחות מכמה מילי-שניות.- ל-API key יש הרשאות מסחר, ללא הרשאות משיכה, ורשימת IP מאושרים אם הבורסה מציעה זאת.
- הריגת התהליך באמצעות
sudo systemctl kill -s SIGKILL tradingbotמחזירה אותו לפעולה בתוךRestartSec. - ניטור ה-heartbeat שולח התראה כאשר עוצרים את הבוט באופן יזום בתוך מרווח זמן אחד.
- הלוגים מוגבלים בגודלם ולמערכת הקבצים של ה-root יש מרווח נשימה ב-
df -h.
הריצו את כל המערכת בסביבת ה-sandbox של הבורסה או במצב paper mode למשך שבוע לפני שימוש בכספים אמיתיים. כל סעיף לעיל ייכשל לפחות פעם אחת במהלך השבוע הזה, וזו בדיוק מטרת השבוע.
FAQ
האם בוט מסחר זקוק לשרת בעל שיהוי נמוך או לשרת Bare Metal?
רק אם אתם מתחרים על מהירות ביצוע מול משתתפים אוטומטיים אחרים באותה זירה, מה שבדרך כלל דורש אירוח משותף (colocation) ולא VPS למטרות כלליות. עבור בוט קמעונאי, זמן הלוך-חזור מושפע בעיקר מהמיקום הגיאוגרפי ומזמן העיבוד של הברוקר עצמו. לכן, בחרו שרת הקרוב לנקודת הקצה של ה-API ובצעו מדידות עם curl ו-mtr לפני שתשלמו על שרת מהיר יותר.
כמה RAM ו-CPU דרושים לבוט מסחר?
רוב הבוטים המריצים אסטרטגיה בודדת מוגבלים על ידי הרשת ונמצאים במצב המתנה בין אירועים. נכון ליולי 2026, 2 ליבות vCPU ו-2 GB של RAM מספיקים עבור בוט Python העוקב אחר כמה מאות מכשירים פיננסיים. הזיכרון הופך למגבלה כאשר שומרים היסטוריית טיקים בתהליך או מריצים מסד נתונים מקומי. לכן, עקבו אחר free -h ואחר הלוגים עבור הודעות OOM kill במקום לנחש.
מדוע ה-API של הבורסה דוחה בקשות עם שגיאת חותמת זמן?
שעון השרת סטה מחוץ לחלון החתימה של הבורסה, שבדרך כלל עומד על כמה שניות. התקינו את chrony, ודאו ש-chronyc tracking מציג היסט (offset) קטן ב-System time וסטטוס סנכרון תקין, והגדירו את המכונה ל-UTC כדי ששינויי שעון קיץ לא ישפיעו עליה. החלפת מפתח ה-API לא תפתור בעיית שעון.
איך למנוע מהבוט לקרוס בלילה מבלי שאדע על כך?
הריצו אותו תחת systemd עם Restart=always ו-StartLimitIntervalSec=0, כך שלולאת קריסה תנסה להפעיל את הבוט מחדש במקום לעצור לצמיתות. לאחר מכן, הוסיפו מנגנון "פעימת לב" (heartbeat) שהבוט שולח בסוף כל לולאה מוצלחת. ה-restart מטפל בתהליך עצמו, בעוד פעימת הלב מזהה מקרים שבהם התהליך חי אך תקוע.
האם ניתן להריץ את הבוט ואת הניטור על אותו VPS?
ניתן, אך הניטור יטעה אתכם ביום שבו זה באמת ישנה, כיוון שתקלה שמפילה את הבוט תפיל גם את הניטור. שמרו את מערכת ההתראות על מכונה נפרדת, רצוי אצל ספק אחר או באזור גיאוגרפי אחר, והשתמשו בשרת של הבוט אך ורק עבור הבוט והלוגים שלו.