מבוא
תארו לעצמכם שהבוט שלכם פותח פוזיציה, השוק מתהפך בחדות, ואתם מגלים זאת 5 שניות מאוחר יותר — כשהמחיר כבר פגע בסטופ-לוס שלכם. עיכוב בניטור הנייד מתורגם ישירות להפסדים. אנו מפתחים אפליקציות מובייל שמתחברות לבוט המסחר שלכם דרך WebSocket — זמן השהיה מתחת ל-200 אלפיות השנייה, מהיר פי 25 מאשר שאילתות REST כל 5 שניות. הניסיון שלנו מראה שתעבורה מיושמת כראוי עם exponential backoff וסנכרון מצב מבטיחה עדכניות נתונים גם ברשתות לא יציבות. צוות המפתחים המוסמכים שלנו ל-iOS, אנדרואיד ו-Flutter מספק את הפרויקט במפתח מלא תוך 5–7 ימי עבודה. עם למעלה מ-5 שנות ניסיון בבניית פתרונות בעלי ביצועים גבוהים למגזר הפיננסי, מקרה זה הוא אחד מהפרויקטים האופייניים שלנו.
כיצד פועלת תעבורת WebSocket
שאילתות REST כל 5 שניות גורמות לעיכוב של עד 5 שניות ולעומס מיותר. WebSocket שומר על חיבור קבוע, ומספק נתונים לפי אירוע. ה-backend של הבוט פולט אירועים: position_opened, position_closed, order_filled, pnl_updated. התיעוד הרשמי של אפל עבור URLSessionWebSocketTask נתמך מאז iOS 13.
השוואת גישות:
| פרמטר | WebSocket | שאילתות REST |
|---|---|---|
| זמן השהיה | 200 אלפיות השנייה | 5+ שניות |
| עומס רשת | מינימלי | גבוה (שאילתות כל 5 שניות) |
| פעולה ברקע | דורש push | רק כשהאפליקציה פעילה |
| מורכבות יישום | בינונית | נמוכה |
ב-iOS, יישום דרך URLSessionWebSocketTask:
actor BotMonitorConnection {
private var webSocketTask: URLSessionWebSocketTask?
private let session = URLSession.shared
var onEvent: ((BotEvent) -> Void)?
func connect(botId: String, token: String) {
let url = URL(string: "wss://api.example.com/bots/\(botId)/stream?token=\(token)")!
webSocketTask = session.webSocketTask(with: url)
webSocketTask?.resume()
startListening()
}
private func startListening() {
webSocketTask?.receive { [weak self] result in
switch result {
case .success(let message):
if case .string(let text) = message, let data = text.data(using: .utf8), let event = try? JSONDecoder().decode(BotEvent.self, from: data) {
self?.onEvent?(event)
}
self?.startListening()
case .failure(let error):
self?.scheduleReconnect()
}
}
}
private func scheduleReconnect() {
Task {
try? await Task.sleep(nanoseconds: 3_000_000_000)
connect(botId: botId, token: token)
}
}
} מדוע Exponential Backoff קריטי למסחר נייד
רשתות ניידות אינן יציבות: רכבת תחתית, מעליות, מעבר בין תאים. אם פשוט תנסו להתחבר מחדש כל שנייה, אתם מסתכנים בריקון הסוללה וחסימת ה-socket. Exponential backoff מגדיל את מרווח החיבור מחדש: 1 שנייה, 2 שניות, 4 שניות, 8 שניות... עד 30 שניות. לאחר חיבור מוצלח, המרווח מתאפס. בנוסף, לאחר חיבור מחדש, הלקוח מבקש את המצב הנוכחי דרך REST (actor BotMonitorConnection { private var webSocketTask: URLSessionWebSocketTask? private let session = URLSession.shared var onEvent: ((BotEvent) -> Void)? func connect(botId: String, token: String) { let url = URL(string: "wss://api.example.com/bots/\(botId)/stream?token=\(token)")! webSocketTask = session.webSocketTask(with: url) webSocketTask?.resume() startListening() } private func startListening() { webSocketTask?.receive { [weak self] result in switch result { case .success(let message): if case .string(let text) = message, let data = text.data(using: .utf8), let event = try? JSONDecoder().decode(BotEvent.self, from: data) { self?.onEvent?(event) } self?.startListening() case .failure(let error): self?.scheduleReconnect() } } } private func scheduleReconnect() { Task { try? await Task.sleep(nanoseconds: 3_000_000_000) connect(botId: botId, token: token) } } } ) כדי להשלים אירועים שהוחמצו.
ב-Flutter עם Riverpod, נוח לחשוף את החיבור כ-GET /bots/{id}/state:
@riverpod
Stream<BotEvent> botEventStream(
BotEventStreamRef ref, String botId) {
final channel = WebSocketChannel.connect(
Uri.parse('wss://api.example.com/bots/$botId/stream'),
);
ref.onDispose(channel.sink.close);
return channel.stream
.map((data) => BotEvent.fromJson(jsonDecode(data as String)))
.handleError((e) => ref.invalidateSelf());
} מה לעשות בעת ניתוק
המשתמש חייב לראות מחוון חיבור: ירוק (חי), אפור (מתחבר מחדש), אדום (לא מקוון). זהו אלמנט מפתח של אמון. אנו מיישמים אלגוריתם שלב אחר שלב:
- בעת ניתוק: חכו שנייה אחת, ואז נסו חיבור מחדש.
- בעת כישלון: הכפילו את זמן ההמתנה עד למקסימום של 30 שניות.
- בעת חיבור מחדש מוצלח: בקשו את המצב הנוכחי דרך REST.
- עדכנו את ממשק המשתמש עם המחוון.
אילו נתונים מוצגים על המסך
האפליקציה מחולקת לשלושה אזורים עיקריים:
פוזיציות פתוחות. זוג, צד (לונג/שורט), גודל, מחיר כניסה, מחיר נוכחי, רווח/הפסד לא ממומש באחוזים ובדולרים. הרווח/הפסד מתעדכן בכל אירוע StreamProvider — אנו מציירים מחדש רק את השורה שהשתנתה, לא את כל הרשימה. באנדרואיד, @riverpod Stream<BotEvent> botEventStream(BotEventStreamRef ref, String botId) { final channel = WebSocketChannel.connect( Uri.parse('wss://api.example.com/bots/$botId/stream'), ); ref.onDispose(channel.sink.close); return channel.stream .map((data) => BotEvent.fromJson(jsonDecode(data as String))) .handleError((e) => ref.invalidateSelf()); } ב-RecyclerView; ב-Flutter, pnl_updated עם מפתחות.
זרם אירועים. N האירועים האחרונים: "פוזיציה נפתחה BTC/USDT לונג 0.01 BTC @ 67,430", "הזמנה בוצעה", "סטופ-לוס הופעל". כולם עם חותמות זמן.
מדדי סשן. מספר עסקאות, רווח/הפסד ממומש כולל, אחוזי הצלחה. מתעדכן בכל DiffUtil. סוגי אירועים בפירוט:
| אירוע | תיאור | תדירות |
|---|---|---|
| position_opened | פוזיציה חדשה נפתחה | בעת אירוע |
| position_closed | פוזיציה נסגרה | בעת אירוע |
| pnl_updated | עדכון רווח/הפסד | כל 500 אלפיות השנייה |
| order_filled | הזמנה בוצעה | בעת אירוע |
התראות Push לאירועים קריטיים
WebSocket הוא הערוץ הראשי למסך הפעיל. אך כשהאפליקציה ברקע, אירועים נשלחים דרך FCM/APNs: סטופ-לוס הופעל, שגיאת בוט, שינוי משמעותי ברווח/הפסד. התראות push אינן מחליפות את הזמן האמיתי אלא משלימות אותו. אנו מגדירים סינון כדי למנוע ספאם: רק אירועים המסומנים כ-ListView.builder על ידי ה-backend.
אמון וניסיון
המהנדסים שלנו מחזיקים בהסמכות של אפל (iOS) וגוגל (אנדרואיד). עם 5+ שנות ניסיון בתחום, סיפקנו למעלה מ-20 פרויקטים למגזר הפיננסי, כולל מסופי מסחר, ניטורי תיקים ולוחות מחוונים לבוטים. כל אפליקציה עוברת בדיקת קוד, בדיקות עומס ובדיקות אבטחה.
מה כלול בעבודה
- לקוח WebSocket עם חיבור מחדש מסוג exponential backoff
- מחוון מצב חיבור (חי/מתחבר מחדש/לא מקוון)
- רשימת פוזיציות פתוחות עם רווח/הפסד חי (עדכונים יעילים)
- זרם אירועים עם גלילה אוטומטית
- סנכרון מצב REST בעת חיבור מחדש
- Push דרך FCM/APNs להתראות ברקע
- תיעוד ומדריך אינטגרציה
לוח זמנים ועלות
זמן הפיתוח הוא 5–7 ימי עבודה. אם ה-backend כבר שולח אירועי WebSocket, החלק הנייד לוקח 4–5 ימים. העלות מחושבת באופן אישי לאחר ניתוח הדרישות והארכיטקטורה.
צרו קשר כדי לדון בפרויקט שלכם. המומחים שלנו יעריכו את הלוגיקה של הבוט שלכם, יציעו ארכיטקטורה אופטימלית ויספקו הערכה מדויקת. קבלו ייעוץ היום.







