הערה: כאשר בורסת קריפטו מחליטה להיכנס לשוק המוסדי, השאלה הראשונה של הלקוחות היא זמינות FIX API. בלעדיו, ברוקרים ראשיים וחברות HFT לא יתחברו—הבוטים שלהם לא יכולים לעבוד עם REST. פרוטוקול FIX הוא התקן למסחר בעל השהיה נמוכה, בשימוש בבורסות מסורתיות מאז סוף המאה ה-20. אנו מפתחים FIX API במתכונת turnkey, ומבטיחים תאימות ל-QuickFIX, תפוקה גבוהה (עד 10,000 הודעות/שנייה), ומודל סשן אמין עם שחזור אוטומטי. הניסיון שלנו כולל הטמעת שרתי FIX לבורסות עם היקפי מסחר יומיים העולים על 100 מיליון דולר. עבור בורסה כזו, מעבר ל-FIX API יכול לחסוך עד 200,000 דולר בשנה בעלויות עסקה. במאמר זה, נצלול לארכיטקטורת שרת FIX, לבעיות אינטגרציה טיפוסיות, ולשלבי העבודה. הזמינו פיתוח FIX API—צרו קשר לייעוץ.
FIX API: מדוע הפיתוח קריטי עבור בורסת קריפטו
FIX הוא פרוטוקול מבוסס טקסט על גבי TCP. הודעה היא קבוצה של שדות tag=value המופרדים על ידי SOH (0x01): 8=FIX.4.4 | 9=178 | 35=D | 49=CLIENT1 | 56=EXCHANGE | 34=123 | 52=20241201-14:30:00.000 | 11=ORDER-001 | 55=BTC/USD | 54=1 | 38=0.1 | 40=2 | 44=42000 | 59=1 | 10=087. תגים מרכזיים: 35=D (New Order Single), 55 — מכשיר, 54 — צד, 38 — כמות, 40 — סוג הזמנה, 44 — מחיר, 59 — Time in Force.
FIX מועדף על פני REST עבור מוסדות מכמה סיבות. פרוטוקול תקני—המערכות שלהם כבר יודעות לעבוד איתו. השהיה נמוכה: עיכובים במיקרו-שניות לעומת מילי-שניות ב-REST—FIX מהיר פי 10–50. מודל סשן אמין עם שחזור אוטומטי לאחר ניתוקים ורצף הודעות.
אילו בעיות FIX API פותר במהלך אינטגרציה?
טיפול במספר סשנים בו-זמנית
כל לקוח מתחבר דרך סשן FIX נפרד עם CompID ייחודי. השרת חייב לעבד אלפי סשנים כראוי מבלי לאבד את סדר ההודעות. רצף (MsgSeqNum) מבטיח שלמות: בעת ניתוק, הלקוח שולח ResendRequest, והשרת משדר מחדש הודעות שהוחמצו. הבדיקות שלנו מראות פעולה יציבה עם 2000+ סשנים בו-זמנית בעומס של 5000 הזמנות/שנייה.
שחזור לאחר ניתוק חיבור
סשן FIX תומך בחיבור מחדש אוטומטי עם שחזור רצף. HeartBtInt (heartbeat) ו-ReconnectInterval מוגדרים בקובץ התצורה. אם סשן אובד, השרת שולח SequenceReset לסנכרון. אנו בודקים תרחישי ניתוק עם 1000 סשנים בו-זמנית, ומבטיחים אפס אובדן נתונים.
אימות ללא אמצעים מובנים
ל-FIX 4.4 אין אימות מובנה. אנו משתמשים בשילוב: רשימת IP לבנה + TLS + שדה מותאם אישית 96 (RawData) למפתח API חתום. דוגמת ולידציה ב-FromAdmin.
כיצד אנו מיישמים שרת FIX
QuickFIX/Go כיישום ראשי
QuickFIX הוא יישום הייחוס של מנוע FIX עם פורטים ל-Go, Java, C++, Python. הגרסה ב-Go (quickfixgo) היא בסיס מצוין לבורסת ייצור.
import (
"github.com/quickfixgo/quickfix"
"github.com/quickfixgo/quickfix/field"
"github.com/quickfixgo/quickfix/fix44"
"github.com/quickfixgo/quickfix/fix44/newordersingle"
)
type FIXApplication struct {
orderEngine *OrderEngine
sessionManager *SessionManager
}
func (app *FIXApplication) OnCreate(sessionID quickfix.SessionID) {
log.Info("FIX session created", "sessionID", sessionID)
}
func (app *FIXApplication) OnLogon(sessionID quickfix.SessionID) {
log.Info("FIX client logged on", "sessionID", sessionID)
app.sessionManager.SetOnline(sessionID)
}
func (app *FIXApplication) OnLogout(sessionID quickfix.SessionID) {
log.Info("FIX client logged out", "sessionID", sessionID)
app.sessionManager.SetOffline(sessionID)
}
func (app *FIXApplication) FromApp(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
msgType, err := msg.Header.GetString(field.NewMsgType())
if err != nil {
return err
}
switch msgType {
case "D": // New Order Single
return app.handleNewOrder(msg, sessionID)
case "F": // Order Cancel Request
return app.handleCancelOrder(msg, sessionID)
case "G": // Order Cancel/Replace Request (amend)
return app.handleAmendOrder(msg, sessionID)
case "H": // Order Status Request
return app.handleStatusRequest(msg, sessionID)
}
return quickfix.NewMessageRejectError("Unknown message type", 35, nil)
} טיפול ב-New Order Single
func (app *FIXApplication) handleNewOrder(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
nos := newordersingle.New(
field.NewClOrdID(""),
field.NewSide(0),
field.NewTransactTime(time.Now()),
field.NewOrdType(0),
)
if err := quickfix.Unmarshal(msg, &nos); err != nil {
return err
}
clOrdID, _ := nos.GetClOrdID()
symbol, _ := nos.GetSymbol()
sideInt, _ := nos.GetSide()
ordType, _ := nos.GetOrdType()
qty, _ := nos.GetOrderQty()
price, _ := nos.GetPrice()
tif, _ := nos.GetTimeInForce()
order := Order{
ClientOrderID: string(clOrdID),
Pair: normalizePair(string(symbol)),
Side: fixSideToInternal(sideInt),
Type: fixOrdTypeToInternal(ordType),
Quantity: decimal.NewFromFloat(float64(qty)),
Price: decimal.NewFromFloat(float64(price)),
TimeInForce: fixTIFToInternal(tif),
}
app.sendExecReport(sessionID, order, ExecTypeNew, OrdStatusPendingNew)
trades, err := app.orderEngine.PlaceOrder(order)
if err != nil {
app.sendExecReport(sessionID, order, ExecTypeRejected, OrdStatusRejected)
return nil
}
for _, trade := range trades {
app.sendFillReport(sessionID, order, trade)
}
if order.RemainingQty().IsPositive() {
status := OrdStatusNew
if len(trades) > 0 {
status = OrdStatusPartiallyFilled
}
app.sendExecReport(sessionID, order, ExecTypeNew, status)
}
return nil
} שליחת Execution Report
func (app *FIXApplication) sendExecReport(sessionID quickfix.SessionID, order Order, execType ExecType, ordStatus OrdStatus) {
report := fix44executionreport.New(
field.NewOrderID(order.ID),
field.NewExecID(generateExecID()),
field.NewExecType(fix44.ExecType(execType)),
field.NewOrdStatus(fix44.OrdStatus(ordStatus)),
field.NewSymbol(denormalizePair(order.Pair)),
field.NewSide(fix44.Side(internalSideToFIX(order.Side))),
field.NewLeavesQty(order.RemainingQty().InexactFloat64(), 8),
field.NewCumQty(order.FilledQty.InexactFloat64(), 8),
field.NewAvgPx(order.AvgPrice().InexactFloat64(), 8),
)
report.SetClOrdID(order.ClientOrderID)
report.SetOrderQty(order.Quantity.InexactFloat64(), 8)
report.SetTransactTime(time.Now())
quickfix.SendToTarget(report.ToMessage(), sessionID)
} מודל סשן ואבטחה
סשן FIX שומר על רצף: לכל הודעה יש MsgSeqNum (34). בעת ניתוק חיבור, הלקוח ממשיך את הסשן עם ה-SeqNum האחרון הידוע. השרת יכול לשלוח ResendRequest (2) או SequenceReset (4).
דוגמת תצורת סשן FIX
func createFIXSettings() *quickfix.Settings {
settings := quickfix.NewSettings()
globalSection := quickfix.NewSessionSettings()
globalSection.Set("FileStorePath", "./fix-sessions")
globalSection.Set("FileLogPath", "./fix-logs")
settings.GlobalSettings().SetGlobalSection(globalSection)
sessionSection := quickfix.NewSessionSettings()
sessionSection.Set(quickfix.BeginString, "FIX.4.4")
sessionSection.Set(quickfix.SenderCompID, "EXCHANGE")
sessionSection.Set(quickfix.TargetCompID, "CLIENT1")
sessionSection.Set("HeartBtInt", "30")
sessionSection.Set("ReconnectInterval", "5")
sessionSection.Set("StartTime", "00:00:00")
sessionSection.Set("EndTime", "00:00:00")
return settings
}ל-FIX 4.4 אין אימות מובנה. גישות סטנדרטיות:
- רשימת IP לבנה: רק כתובות IP מורשות מתחברות לפורט FIX.
- TLS: הצפנת החיבור (FIX over SSL).
- התחברות עם סיסמה: שדה 96 (RawData) או תג מותאם אישית למפתח API חתום.
func (app *FIXApplication) FromAdmin(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
msgType, _ := msg.Header.GetString(field.NewMsgType())
if msgType == "A" { // Logon
apiKey, _ := msg.Body.GetString(9001)
signature, _ := msg.Body.GetString(9002)
timestamp, _ := msg.Body.GetString(9003)
if !app.auth.Verify(apiKey, signature, timestamp) {
return quickfix.NewMessageRejectError("Authentication failed", 58, nil)
}
app.sessionManager.SetAPIKey(sessionID, apiKey)
}
return nil
} אבטחת חיבור FIX: שלוש שכבות הגנה
אנו מבטיחים הגנה בשלוש רמות: תעבורה (TLS), רשת (רשימת IP לבנה), ויישום (אימות חתום). בנוסף, אנו מיישמים ביקורת סשנים ו-Drop Copy לציות. זהו התקן עבור בורסות העובדות עם לקוחות מוסדיים.
היקף העבודה לפיתוח FIX API
- פיתוח שרת FIX 4.4 ב-Go (QuickFIX)
- הטמעת הודעות סטנדרטיות: New Order, Cancel, Amend, Execution Reports
- ערוץ Market Data (מינוי לספר הזמנות ועסקאות)
- אבטחה: TLS, רשימת IP לבנה, אימות מפתח
- Drop Copy לציות
- תיעוד ובדיקות (עומס, רגרסיה)
- הכשרת צוות ותמיכה במהלך ההשקה
תהליך ולוחות זמנים
- ניתוח: לימוד הדרישות והארכיטקטורה הקיימת שלך.
- עיצוב: פיתוח תכנית סשן, רצף הודעות, ומדיניות אבטחה.
- יישום: כתיבת קוד—מפענוח הודעות ועד אינטראקציה עם מנוע ההתאמה.
- בדיקות: עומס (1000+ הזמנות/שנייה) ורגרסיה.
- פריסה: השקה, ניטור, והכשרת הצוות שלך.
לוחות זמנים משוערים: מ-4 שבועות לאינטגרציה בסיסית ועד 2–3 חודשים לפתרון מלא מוכן לייצור.
| תכונה | FIX | REST |
|---|---|---|
| השהיה | מיקרו-שניות (<100 μs) | מילי-שניות |
| אמינות | שחזור מובנה | מורכב יותר |
| אימות | חיצוני (TLS + מפתחות) | מפתחות API |
| תקינה | פרוטוקול יחיד | יישומים שונים |
| שלב | משך |
|---|---|
| ניתוח ועיצוב | 1–2 שבועות |
| פיתוח שרת בסיסי | 3–4 שבועות |
| Market Data ו-Drop Copy | 2–3 שבועות |
| בדיקות (עומס, רגרסיה) | שבועיים |
| פריסה והכשרה | שבוע |
טעויות נפוצות בפיתוח FIX API
רצף שגוי: אם MsgSeqNum יוצא מסנכרון, הסשן נכנס למצב שבור. השתמשו באחסון קובץ או מסד נתונים עבור SeqNum, לא בזיכרון. התעלמות מ-HeartBtInt: לקוחות מתנתקים בהיעדר heartbeats. הגדירו HeartBtInt ל-30 שניות וטפלו ב-MissedHeartBeat. חוסר ResendRequest: בעת ניתוק, הלקוח חייב לבקש שידור חוזר. ודאו שהשרת מאחסן את כל ההודעות לשידור חוזר.
קבלו ייעוץ על FIX API עבור הבורסה שלכם—צרו קשר להערכת היקף העבודה. בקשו אינטגרציית בדיקה: נספק גישה למופע שרת FIX עבור המפתחים שלכם.
מפרט פרוטוקול FIX: פרוטוקול FIX







