פיתוח ויזואליזציה של זרימת הזמנות (תרשים Footprint)

סוחרים לעיתים קרובות מפספסים איתותים חשובים כאשר הם רואים רק נרות סטנדרטיים, שמסתירים את הקרב האמיתי בין קונים למוכרים. אנו מפתחים ויזואליזציה של זרימת הזמנות המבוססת על Footprint Chart, וחושפים את המבנה הפנימי של השוק באמצעות ניתוח דלתא וזיהוי חוסר איזון. הצוות שלנו מספק את הפרויקט במפתח מלא—מהקונספט ועד היישום—ומבטיח פתרון אמין שגדל עם העסק שלך.

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1481
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1336
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1034
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1293
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    738
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1032

פיתוח ויזואליזציה של זרימת הזמנות (תרשים Footprint)

כאשר מערכת המסחר שלך רואה רק OHLCV, אתה עיוור לקרב שמתרחש בתוך כל נר. תרשימי Footprint חושפים את המיקרו-מבנה: בכל רמת מחיר, אתה רואה בדיוק כמה חוזים נקנו ונמכרו. בילינו למעלה מ-10 שנים בפיתוח כלי מסחר לקרנות ולסוחרים מקצועיים, ואנחנו יודעים להפוך נתוני tick גולמיים ל-Footprint ברור שמעניק לך יתרון אמיתי.

מה Footprint חושף ש-OHLCV מסתיר

נר רגיל מציג פתיחה, גבוה, נמוך, סגירה ונפח כולל. נר Footprint מציג מה קרה בכל רמת מחיר: לדוגמה, ב-$42,050 היו 8.5 BTC של קניות אגרסיביות ו-2.1 BTC של מכירות אגרסיביות, בעוד שב-$42,100 היו 3.2 קניות ו-12.4 מכירות. זהו ה-Footprint האמיתי של משתתפי השוק.

מושגי מפתח: נפח Ask (קניות אגרסיביות), נפח Bid (מכירות אגרסיביות), דלתא (Ask - Bid), חוסר איזון (צד אחד שולט בסף מסוים, בדרך כלל פי 3), ונקודת שליטה (POC — רמת המחיר עם הנפח הכולל המקסימלי).

כיצד אנו מסווגים עסקאות ל-Footprint מדויק

ה-Footprint בנוי מנתוני tick — כל עסקה בודדת. כל עסקה חייבת להיות מסווגת כקנייה או מכירה אגרסיבית. אנו משתמשים בכלל הציטוט כאשר bid/ask זמין, ונופלים חזרה לכלל ה-tick. בורסות רבות מספקות דגל כיוון ישירות (לדוגמה, type Trade struct { Price decimal.Decimal Quantity decimal.Decimal Timestamp int64 IsBuy bool // true = aggressive buy (executed at ask) } // Классификация по tick rule или quote rule type TradeClassifier struct { lastPrice decimal.Decimal lastBid decimal.Decimal lastAsk decimal.Decimal } // Quote rule: более точный метод (требует bid/ask в момент сделки) func (tc *TradeClassifier) ClassifyByQuote(trade RawTrade) bool { midPrice := tc.lastBid.Add(tc.lastAsk).Div(decimal.New(2, 0)) return trade.Price.GreaterThanOrEqual(midPrice) // >= mid = buy } // Tick rule: fallback когда bid/ask недоступны func (tc *TradeClassifier) ClassifyByTick(trade RawTrade) bool { if trade.Price.GreaterThan(tc.lastPrice) { return true // uptick = buy } if trade.Price.LessThan(tc.lastPrice) { return false // downtick = sell } // Zero tick — используем предыдущую классификацию return tc.lastWasBuy } של Binance).

type Trade struct {
    Price     decimal.Decimal
    Quantity  decimal.Decimal
    Timestamp int64
    IsBuy     bool // true = aggressive buy (executed at ask)
}

// Классификация по tick rule или quote rule
type TradeClassifier struct {
    lastPrice decimal.Decimal
    lastBid   decimal.Decimal
    lastAsk   decimal.Decimal
}

// Quote rule: более точный метод (требует bid/ask в момент сделки)
func (tc *TradeClassifier) ClassifyByQuote(trade RawTrade) bool {
    midPrice := tc.lastBid.Add(tc.lastAsk).Div(decimal.New(2, 0))
    return trade.Price.GreaterThanOrEqual(midPrice) // >= mid = buy
}

// Tick rule: fallback когда bid/ask недоступны
func (tc *TradeClassifier) ClassifyByTick(trade RawTrade) bool {
    if trade.Price.GreaterThan(tc.lastPrice) {
        return true // uptick = buy
    }
    if trade.Price.LessThan(tc.lastPrice) {
        return false // downtick = sell
    }
    // Zero tick — используем предыдущую классификацию
    return tc.lastWasBuy
}

השוואת שיטות סיווג

שיטה דיוק נתונים נדרשים
כלל הציטוט גבוה Bid/ask בזמן העסקה
כלל ה-tick בינוני מחיר בלבד
דגל הבורסה (isBuyerMaker) גבוה שדה מהבורסה

למה Footprint נותן פי 10 יותר מידע מ-OHLCV

נר OHLCV אחד מכיל 4 מספרים. נר Footprint מכיל עשרות מספרים בכל רמת מחיר, וחושף את המיקרו-מבנה של השוק: מי שולט בכל tick. זהו ערך עצום למסחר אלגוריתמי. השוואה: OHLCV נותן נפח כולל; footprint נותן התפלגות נפח על פני מחירים.

צבירת נר Footprint

type FootprintLevel struct {
    Price decimal.Decimal
    BidVol decimal.Decimal // агрессивные продажи
    AskVol decimal.Decimal // агрессивные покупки
    Delta decimal.Decimal // AskVol - BidVol
}

type FootprintCandle struct {
    Timestamp int64
    Open decimal.Decimal
    High decimal.Decimal
    Low decimal.Decimal
    Close decimal.Decimal
    Volume decimal.Decimal
    Delta decimal.Decimal // суммарная delta свечи
    Levels map[string]*FootprintLevel // price -> level data
    POC decimal.Decimal // уровень с макс. объёмом
    BuyPOC decimal.Decimal // уровень с макс. ask volume
    SellPOC decimal.Decimal // уровень с макс. bid volume
}

type FootprintBuilder struct {
    tickSize decimal.Decimal // шаг цены для группировки (например 10 USD для BTC)
    candles map[int64]*FootprintCandle // timestamp -> candle
    mu sync.Mutex
}

func (fb *FootprintBuilder) AddTrade(trade Trade, timeframe time.Duration) {
    fb.mu.Lock()
    defer fb.mu.Unlock()
    // Вычисляем bucket для временного таймфрейма
    bucket := (trade.Timestamp / int64(timeframe)) * int64(timeframe)
    candle := fb.getOrCreateCandle(bucket, trade.Price)
    // Группируем цену по тик-размеру
    priceBucket := trade.Price.Div(fb.tickSize).Floor().Mul(fb.tickSize)
    level := fb.getOrCreateLevel(candle, priceBucket)
    if trade.IsBuy {
        level.AskVol = level.AskVol.Add(trade.Quantity)
    } else {
        level.BidVol = level.BidVol.Add(trade.Quantity)
    }
    level.Delta = level.AskVol.Sub(level.BidVol)
    // Обновляем OHLCV
    candle.Volume = candle.Volume.Add(trade.Quantity)
    candle.Delta = candle.Delta.Add(trade.IsBuyDelta(trade.Quantity))
    if trade.Price.GreaterThan(candle.High) {
        candle.High = trade.Price
    }
    if trade.Price.LessThan(candle.Low) {
        candle.Low = trade.Price
    }
    candle.Close = trade.Price
    // Обновляем POC
    candle.POC = fb.findPOC(candle)
}

func (fb *FootprintBuilder) findPOC(candle *FootprintCandle) decimal.Decimal {
    var maxVol decimal.Decimal
    var poc decimal.Decimal
    for price, level := range candle.Levels {
        total := level.AskVol.Add(level.BidVol)
        if total.GreaterThan(maxVol) {
            maxVol = total
            poc, _ = decimal.NewFromString(price)
        }
    }
    return poc
}

זיהוי חוסר איזון: האות המרכזי

חוסר איזון הוא דפוס ה-Footprint המרכזי. רמה שבה נפח ask הוא פי 3 מנפח bid היא "רצפת זכוכית" (קונים שלטו). רמה שבה נפח bid הוא פי 3 מנפח ask היא "תקרת זכוכית".

type ImbalanceDetector struct {
    threshold decimal.Decimal // обычно 300% (3x)
}

type Imbalance struct {
    Price  decimal.Decimal
    Type   string // "bid" или "ask"
    Ratio  decimal.Decimal
    Volume decimal.Decimal
}

func (id *ImbalanceDetector) FindImbalances(candle *FootprintCandle) []Imbalance {
    var imbalances []Imbalance
    sortedLevels := candle.SortedLevels() // по цене ascending
    for i, level := range sortedLevels {
        if i == 0 {
            continue
        }
        below := sortedLevels[i-1]
        // Сравниваем ask текущего уровня с bid уровня ниже
        // "Stacked imbalance" — несколько подряд
        if level.AskVol.IsPositive() && below.BidVol.IsPositive() {
            ratio := level.AskVol.Div(below.BidVol).Mul(decimal.New(100, 0))
            if ratio.GreaterThan(id.threshold) {
                imbalances = append(imbalances, Imbalance{
                    Price:  level.Price,
                    Type:   "ask",
                    Ratio:  ratio,
                    Volume: level.AskVol,
                })
            }
        }
    }
    return imbalances
}

עיבוד חזיתי: Canvas בקנה מידה גדול

Footprint מורכב יותר מנרות רגילים: כל רמת מחיר מכילה מספרים. HTML Canvas הוא הדרך היחידה היעילה לעיבוד מאות נרות עם פירוט מלא.

class FootprintRenderer {
    private canvas: HTMLCanvasElement;
    private ctx: CanvasRenderingContext2D;

    renderCandle(candle: FootprintCandle, x: number, candleWidth: number, priceToY: (price: number) => number) {
        const ctx = this.ctx;
        const levels = candle.getSortedLevels();
        const levelHeight = Math.abs(priceToY(levels[0].price) - priceToY(levels[1]?.price || levels[0].price - candle.tickSize));

        for (const level of levels) {
            const y = priceToY(level.price);
            const maxLevelVol = candle.maxLevelVolume;
            const askWidth = (level.askVol / maxLevelVol) * (candleWidth * 0.45);
            const bidWidth = (level.bidVol / maxLevelVol) * (candleWidth * 0.45);

            ctx.fillStyle = 'rgba(0, 177, 94, 0.3)';
            ctx.fillRect(x + candleWidth/2, y, askWidth, levelHeight - 1);

            ctx.fillStyle = 'rgba(232, 66, 66, 0.3)';
            ctx.fillRect(x + candleWidth/2 - bidWidth, y, bidWidth, levelHeight - 1);

            if (level.price === candle.poc) {
                ctx.strokeStyle = '#FFD700';
                ctx.lineWidth = 1;
                ctx.strokeRect(x, y, candleWidth, levelHeight - 1);
            }

            if (levelHeight > 12) {
                ctx.fillStyle = '#6b7087';
                ctx.font = `${Math.min(levelHeight - 2, 10)}px JetBrains Mono`;
                ctx.textAlign = 'left';
                ctx.fillText(formatVol(level.bidVol), x + 2, y + levelHeight - 3);
                ctx.textAlign = 'right';
                ctx.fillText(formatVol(level.askVol), x + candleWidth - 2, y + levelHeight - 3);
            }

            if (level.imbalanceType === 'ask') {
                ctx.fillStyle = 'rgba(0, 177, 94, 0.8)';
                ctx.fillRect(x, y, 3, levelHeight);
            } else if (level.imbalanceType === 'bid') {
                ctx.fillStyle = 'rgba(232, 66, 66, 0.8)';
                ctx.fillRect(x, y, 3, levelHeight);
            }
        }
    }

    renderDeltaBar(candle: FootprintCandle, x: number, candleWidth: number, baseY: number) {
        const ctx = this.ctx;
        const delta = candle.delta;
        const maxDelta = this.maxAbsDelta;
        const barWidth = Math.abs(delta / maxDelta) * (candleWidth / 2);
        const color = delta >= 0 ? '#00B15E' : '#E84242';

        ctx.fillStyle = color;
        if (delta >= 0) {
            ctx.fillRect(x + candleWidth / 2, baseY, barWidth, 8);
        } else {
            ctx.fillRect(x + candleWidth / 2 - barWidth, baseY, barWidth, 8);
        }
    }
}

פרופיל דלתא בתוך נר

דלתא מצטברת על פני פסים פנימיים מראה את המאבק בין קונים למוכרים:

function calculateCumulativeDelta(trades: Trade[], bucketSize: number): CumDeltaPoint[] {
    const points: CumDeltaPoint[] = [];
    let cumDelta = 0;
    for (const trade of trades) {
        cumDelta += trade.isBuy ? trade.quantity : -trade.quantity;
        points.push({ ts: trade.timestamp, price: trade.price, cumDelta });
    }
    return points;
}

אחסון נתונים וביצועים

נתוני Footprint גדולים בהרבה מ-OHLCV. עבור BTC/USDT 1m עם tick של $10: כ-15 רמות לכל נר. זה 1,440 נרות × 15 רמות × 2 ערכים = 43,200 רשומות ליום עבור מסגרת זמן אחת. אחסון אופטימלי הוא TimescaleDB עם דחיסה, שמקטין את הגודל פי 5–20. המערכות היצרניות שלנו מטפלות ב-8,000 עסקאות בשנייה לכל ליבה, ומאפשרות עיבוד בזמן אמת של מסגרות זמן מרובות.

פירוט: בחירת גודל ה-tick גודל ה-tick קובע את צעד המחיר לקיבוץ רמות. עבור BTC/USDT אנו משתמשים בדרך כלל ב-$10; עבור אלטקוינים, $0.01. הבחירה תלויה בתנודתיות ובנזילות.

התהליך שלנו לבניית מערכת Footprint

  1. ניתוח דרישות וזיהוי מקורות נתונים (API של בורסות)
  2. עיצוב סכמת אחסון וארכיטקטורת מסווג
  3. יישום ליבה: מסווג עסקאות, בונה, מזהה חוסר איזון
  4. חזית: רנדרר Canvas עם זום וגלילה
  5. אינטגרציה עם נתונים בזמן אמת דרך WebSocket
  6. בדיקות היסטוריות ואימות
  7. פריסה עם ניטור והתראות

מה אתה מקבל

  • קוד מקור מלא עם הערות
  • תיעוד API וארכיטקטורה
  • דוגמאות שימוש עם נתוני בדיקה
  • גישה לריפוזיטורי עם CI/CD
  • הדרכת צוות
  • 3 חודשי תמיכה לאחר מסירה

לוחות זמנים ועלות

לוחות הזמנים תלויים בנפח הנתונים ובמורכבות. הערכות:

  • תרשים Footprint בסיסי לזוג אחד: 2–3 חודשים
  • פלטפורמה מלאה עם מסגרות זמן מרובות, התראות ובדיקות היסטוריות: 4–6 חודשים

העלות מחושבת באופן אישי. למהנדסים שלנו יש ניסיון של למעלה מ-10 שנים בפיתוח מערכות מסחר, עם מסירה של למעלה מ-15 פרויקטים לקרנות ולסוחרים מקצועיים. צור קשר להערכת פרויקט חינמית — נספק הערכה וייעוץ.