diff --git a/README.md b/README.md index f05dd08..8471558 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,8 @@ CREATE TABLE five_second_features ( realized_vol REAL NOT NULL, -- Std dev of tick-to-tick log returns ofi REAL NOT NULL, -- Buy volume − Sell volume volume_sum REAL NOT NULL, -- Total volume in bucket - close_price REAL NOT NULL -- Last trade price in bucket + close_price REAL NOT NULL, -- Last trade price in bucket + vwap REAL NOT NULL -- Volume-Weighted Average Price in bucket ); ``` diff --git a/aggregator.go b/aggregator.go index 954f482..5dc86e6 100644 --- a/aggregator.go +++ b/aggregator.go @@ -92,10 +92,10 @@ func (a *Aggregator) flushBucket() { _, err := a.featDB.Exec(` INSERT OR IGNORE INTO five_second_features - (timestamp, log_return, realized_vol, ofi, volume_sum, close_price) - VALUES (?, ?, ?, ?, ?, ?) + (timestamp, log_return, realized_vol, ofi, volume_sum, close_price, vwap) + VALUES (?, ?, ?, ?, ?, ?, ?) `, bucket.Timestamp, bucket.LogReturn, bucket.RealizedVol, - bucket.OFI, bucket.VolumeSum, bucket.ClosePrice) + bucket.OFI, bucket.VolumeSum, bucket.ClosePrice, bucket.VWAP) if err != nil { log.Printf("[aggregator] Failed to write feature bucket: %v", err) @@ -118,10 +118,12 @@ func (a *Aggregator) computeFeatures(ticks []Tick) FeatureBucket { } logReturn := math.Log(closePrice / refPrice) - // Order Flow Imbalance (OFI) and total volume + // Order Flow Imbalance (OFI), total volume, and sum of price * volume var buyVol, sellVol, volumeSum float64 + var priceVolumeSum float64 for _, t := range ticks { volumeSum += t.Volume + priceVolumeSum += t.Price * t.Volume if t.Side == "Buy" { buyVol += t.Volume } else { @@ -130,6 +132,11 @@ func (a *Aggregator) computeFeatures(ticks []Tick) FeatureBucket { } ofi := buyVol - sellVol + vwap := closePrice + if volumeSum > 0 { + vwap = priceVolumeSum / volumeSum + } + // Realized volatility: standard deviation of tick-to-tick log returns realizedVol := 0.0 if n > 1 { @@ -164,5 +171,6 @@ func (a *Aggregator) computeFeatures(ticks []Tick) FeatureBucket { OFI: ofi, VolumeSum: volumeSum, ClosePrice: closePrice, + VWAP: vwap, } } diff --git a/storage.go b/storage.go index 78090ef..8d9a1ee 100644 --- a/storage.go +++ b/storage.go @@ -116,7 +116,8 @@ func (sm *StorageManager) initFeaturesDB() error { realized_vol REAL NOT NULL, ofi REAL NOT NULL, volume_sum REAL NOT NULL, - close_price REAL NOT NULL + close_price REAL NOT NULL, + vwap REAL NOT NULL ); `) return err diff --git a/types.go b/types.go index 54b7bf0..ab1fa4b 100644 --- a/types.go +++ b/types.go @@ -16,6 +16,7 @@ type FeatureBucket struct { OFI float64 // Net volume (Buy volume - Sell volume) VolumeSum float64 // Total volume exchanged ClosePrice float64 // Final transaction price in the bucket + VWAP float64 // Volume-Weighted Average Price in the bucket } // BybitWSMessage represents the top-level WebSocket message from Bybit V5 publicTrade.