feat: create v2-prep branch with comprehensive planning
Restructured project for V2 refactor: **Structure Changes:** - Moved all V1 code to orig/ folder (preserved with git mv) - Created docs/planning/ directory - Added orig/README_V1.md explaining V1 preservation **Planning Documents:** - 00_V2_MASTER_PLAN.md: Complete architecture overview - Executive summary of critical V1 issues - High-level component architecture diagrams - 5-phase implementation roadmap - Success metrics and risk mitigation - 07_TASK_BREAKDOWN.md: Atomic task breakdown - 99+ hours of detailed tasks - Every task < 2 hours (atomic) - Clear dependencies and success criteria - Organized by implementation phase **V2 Key Improvements:** - Per-exchange parsers (factory pattern) - Multi-layer strict validation - Multi-index pool cache - Background validation pipeline - Comprehensive observability **Critical Issues Addressed:** - Zero address tokens (strict validation + cache enrichment) - Parsing accuracy (protocol-specific parsers) - No audit trail (background validation channel) - Inefficient lookups (multi-index cache) - Stats disconnection (event-driven metrics) Next Steps: 1. Review planning documents 2. Begin Phase 1: Foundation (P1-001 through P1-010) 3. Implement parsers in Phase 2 4. Build cache system in Phase 3 5. Add validation pipeline in Phase 4 6. Migrate and test in Phase 5 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
242
orig/pkg/validation/price_impact_validator_test.go
Normal file
242
orig/pkg/validation/price_impact_validator_test.go
Normal file
@@ -0,0 +1,242 @@
|
||||
package validation
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultPriceImpactThresholds(t *testing.T) {
|
||||
thresholds := DefaultPriceImpactThresholds()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
value float64
|
||||
expected float64
|
||||
}{
|
||||
{"Low threshold", thresholds.LowThreshold, 0.5},
|
||||
{"Medium threshold", thresholds.MediumThreshold, 2.0},
|
||||
{"High threshold", thresholds.HighThreshold, 5.0},
|
||||
{"Extreme threshold", thresholds.ExtremeThreshold, 10.0},
|
||||
{"Max acceptable", thresholds.MaxAcceptable, 15.0},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.value != tt.expected {
|
||||
t.Errorf("%s = %v, want %v", tt.name, tt.value, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCategorizePriceImpact(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
priceImpact float64
|
||||
expectedLevel PriceImpactRiskLevel
|
||||
}{
|
||||
{"Negligible impact", 0.05, RiskLevelNegligible},
|
||||
{"Low impact", 0.3, RiskLevelLow},
|
||||
{"Medium impact", 1.0, RiskLevelMedium},
|
||||
{"High impact", 3.0, RiskLevelHigh},
|
||||
{"Extreme impact", 7.0, RiskLevelExtreme},
|
||||
{"Unacceptable impact", 20.0, RiskLevelUnacceptable},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := validator.ValidatePriceImpact(tt.priceImpact)
|
||||
if result.RiskLevel != tt.expectedLevel {
|
||||
t.Errorf("Risk level = %v, want %v", result.RiskLevel, tt.expectedLevel)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldRejectTrade(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
priceImpact float64
|
||||
shouldReject bool
|
||||
}{
|
||||
{"Low impact - accept", 0.5, false},
|
||||
{"Medium impact - accept", 2.0, false},
|
||||
{"High impact - accept", 5.0, false},
|
||||
{"Extreme impact - accept", 10.0, false},
|
||||
{"At max threshold - accept", 15.0, false},
|
||||
{"Above max threshold - reject", 15.1, true},
|
||||
{"Very high - reject", 30.0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := validator.ShouldRejectTrade(tt.priceImpact)
|
||||
if result != tt.shouldReject {
|
||||
t.Errorf("ShouldRejectTrade(%v) = %v, want %v", tt.priceImpact, result, tt.shouldReject)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldSplitTrade(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
priceImpact float64
|
||||
shouldSplit bool
|
||||
}{
|
||||
{"Negligible - no split", 0.1, false},
|
||||
{"Low - no split", 0.5, false},
|
||||
{"Just below medium - no split", 1.9, false},
|
||||
{"At medium threshold - split", 2.0, true},
|
||||
{"High - split", 5.0, true},
|
||||
{"Extreme - split", 10.0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := validator.ShouldSplitTrade(tt.priceImpact)
|
||||
if result != tt.shouldSplit {
|
||||
t.Errorf("ShouldSplitTrade(%v) = %v, want %v", tt.priceImpact, result, tt.shouldSplit)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRecommendedSplitCount(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
priceImpact float64
|
||||
expectedSplit int
|
||||
}{
|
||||
{"Low impact - no split", 0.5, 1},
|
||||
{"Medium impact - split in 2", 2.5, 2},
|
||||
{"High impact - split in 4", 6.0, 4},
|
||||
{"Extreme impact - split in 8", 12.0, 8},
|
||||
{"Unacceptable - reject (0)", 20.0, 0},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := validator.GetRecommendedSplitCount(tt.priceImpact)
|
||||
if result != tt.expectedSplit {
|
||||
t.Errorf("GetRecommendedSplitCount(%v) = %v, want %v", tt.priceImpact, result, tt.expectedSplit)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateMaxTradeSize(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
|
||||
liquidity := big.NewInt(1000000) // 1M units of liquidity
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
liquidity *big.Int
|
||||
targetPriceImpact float64
|
||||
expectedApproximate int64 // Approximate expected value
|
||||
}{
|
||||
{"0.5% impact", liquidity, 0.5, 5025}, // ~0.5% of 1M
|
||||
{"1% impact", liquidity, 1.0, 10101}, // ~1% of 1M
|
||||
{"2% impact", liquidity, 2.0, 20408}, // ~2% of 1M
|
||||
{"5% impact", liquidity, 5.0, 52631}, // ~5% of 1M
|
||||
{"10% impact", liquidity, 10.0, 111111}, // ~10% of 1M
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := validator.CalculateMaxTradeSize(tt.liquidity, tt.targetPriceImpact)
|
||||
|
||||
// Check if result is within 5% of expected value
|
||||
resultInt64 := result.Int64()
|
||||
lowerBound := int64(float64(tt.expectedApproximate) * 0.95)
|
||||
upperBound := int64(float64(tt.expectedApproximate) * 1.05)
|
||||
|
||||
if resultInt64 < lowerBound || resultInt64 > upperBound {
|
||||
t.Errorf("CalculateMaxTradeSize() = %v, expected approximately %v (±5%%)", result, tt.expectedApproximate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePriceImpactWithLiquidity(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
|
||||
liquidity := big.NewInt(1000000) // 1M units
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tradeSize *big.Int
|
||||
liquidity *big.Int
|
||||
expectedRiskLevel PriceImpactRiskLevel
|
||||
}{
|
||||
{"Small trade", big.NewInt(1000), liquidity, RiskLevelNegligible},
|
||||
{"Medium trade", big.NewInt(20000), liquidity, RiskLevelMedium},
|
||||
{"Large trade", big.NewInt(100000), liquidity, RiskLevelExtreme},
|
||||
{"Very large trade", big.NewInt(500000), liquidity, RiskLevelUnacceptable},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := validator.ValidatePriceImpactWithLiquidity(tt.tradeSize, tt.liquidity)
|
||||
if result.RiskLevel != tt.expectedRiskLevel {
|
||||
t.Errorf("Risk level = %v, want %v (price impact: %.2f%%)",
|
||||
result.RiskLevel, tt.expectedRiskLevel, result.PriceImpact)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConservativeThresholds(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(ConservativePriceImpactThresholds())
|
||||
|
||||
// Test that conservative thresholds are more strict
|
||||
// With conservative: High=1.0%, Extreme=2.0%
|
||||
// So 1.0% exactly is at the boundary and goes to Extreme
|
||||
result := validator.ValidatePriceImpact(1.0)
|
||||
|
||||
if result.RiskLevel != RiskLevelExtreme {
|
||||
t.Errorf("With conservative thresholds, 1%% should be Extreme risk, got %v", result.RiskLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAggressiveThresholds(t *testing.T) {
|
||||
validator := NewPriceImpactValidator(AggressivePriceImpactThresholds())
|
||||
|
||||
// Test that aggressive thresholds are more lenient
|
||||
// With aggressive: Low=1.0%, Medium=3.0%
|
||||
// So 2.0% falls in the Medium range (between 1.0 and 3.0)
|
||||
result := validator.ValidatePriceImpact(2.0)
|
||||
|
||||
if result.RiskLevel != RiskLevelMedium {
|
||||
t.Errorf("With aggressive thresholds, 2%% should be Medium risk, got %v", result.RiskLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkValidatePriceImpact(b *testing.B) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
validator.ValidatePriceImpact(2.5)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkValidatePriceImpactWithLiquidity(b *testing.B) {
|
||||
validator := NewPriceImpactValidator(DefaultPriceImpactThresholds())
|
||||
tradeSize := big.NewInt(50000)
|
||||
liquidity := big.NewInt(1000000)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
validator.ValidatePriceImpactWithLiquidity(tradeSize, liquidity)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user