mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-06 12:30:59 +08:00
Implements Tasks 6-9 for grid market regime awareness: - Task 6: classifyRegimeLevel with Bollinger/ATR thresholds - Task 7: detectBoxBreakout for multi-period box breakouts - Task 8: confirmBreakout with 3-candle confirmation logic - Task 9: getBreakoutAction mapping breakout levels to actions
123 lines
3.3 KiB
Go
123 lines
3.3 KiB
Go
package trader
|
|
|
|
import (
|
|
"nofx/market"
|
|
"testing"
|
|
)
|
|
|
|
func TestClassifyRegimeLevel(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
bollingerWidth float64
|
|
atr14Pct float64
|
|
expected market.RegimeLevel
|
|
}{
|
|
{"narrow", 1.5, 0.8, market.RegimeLevelNarrow},
|
|
{"standard", 2.5, 1.5, market.RegimeLevelStandard},
|
|
{"wide", 3.5, 2.5, market.RegimeLevelWide},
|
|
{"volatile", 5.0, 4.0, market.RegimeLevelVolatile},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := classifyRegimeLevel(tt.bollingerWidth, tt.atr14Pct)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected %v, got %v", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDetectBoxBreakout(t *testing.T) {
|
|
box := &market.BoxData{
|
|
ShortUpper: 100,
|
|
ShortLower: 90,
|
|
MidUpper: 105,
|
|
MidLower: 85,
|
|
LongUpper: 110,
|
|
LongLower: 80,
|
|
CurrentPrice: 95,
|
|
}
|
|
|
|
// No breakout
|
|
level, direction := detectBoxBreakout(box)
|
|
if level != market.BreakoutNone {
|
|
t.Errorf("Expected no breakout, got %v", level)
|
|
}
|
|
|
|
// Short breakout up
|
|
box.CurrentPrice = 101
|
|
level, direction = detectBoxBreakout(box)
|
|
if level != market.BreakoutShort || direction != "up" {
|
|
t.Errorf("Expected short breakout up, got %v %v", level, direction)
|
|
}
|
|
|
|
// Mid breakout down
|
|
box.CurrentPrice = 84
|
|
level, direction = detectBoxBreakout(box)
|
|
if level != market.BreakoutMid || direction != "down" {
|
|
t.Errorf("Expected mid breakout down, got %v %v", level, direction)
|
|
}
|
|
|
|
// Long breakout up
|
|
box.CurrentPrice = 112
|
|
level, direction = detectBoxBreakout(box)
|
|
if level != market.BreakoutLong || direction != "up" {
|
|
t.Errorf("Expected long breakout up, got %v %v", level, direction)
|
|
}
|
|
}
|
|
|
|
func TestBreakoutConfirmation(t *testing.T) {
|
|
state := &BreakoutState{
|
|
Level: market.BreakoutNone,
|
|
Direction: "",
|
|
ConfirmCount: 0,
|
|
}
|
|
|
|
// First detection
|
|
confirmed := confirmBreakout(state, market.BreakoutShort, "up")
|
|
if confirmed || state.ConfirmCount != 1 {
|
|
t.Errorf("Expected not confirmed, count=1, got confirmed=%v count=%d", confirmed, state.ConfirmCount)
|
|
}
|
|
|
|
// Second confirmation
|
|
confirmed = confirmBreakout(state, market.BreakoutShort, "up")
|
|
if confirmed || state.ConfirmCount != 2 {
|
|
t.Errorf("Expected not confirmed, count=2, got confirmed=%v count=%d", confirmed, state.ConfirmCount)
|
|
}
|
|
|
|
// Third confirmation - should confirm
|
|
confirmed = confirmBreakout(state, market.BreakoutShort, "up")
|
|
if !confirmed || state.ConfirmCount != 3 {
|
|
t.Errorf("Expected confirmed, count=3, got confirmed=%v count=%d", confirmed, state.ConfirmCount)
|
|
}
|
|
|
|
// Reset on price return
|
|
state.ConfirmCount = 2
|
|
confirmed = confirmBreakout(state, market.BreakoutNone, "")
|
|
if state.ConfirmCount != 0 {
|
|
t.Errorf("Expected count reset to 0, got %d", state.ConfirmCount)
|
|
}
|
|
}
|
|
|
|
func TestGetBreakoutAction(t *testing.T) {
|
|
tests := []struct {
|
|
level market.BreakoutLevel
|
|
expected BreakoutAction
|
|
}{
|
|
{market.BreakoutNone, BreakoutActionNone},
|
|
{market.BreakoutShort, BreakoutActionReducePosition},
|
|
{market.BreakoutMid, BreakoutActionPauseGrid},
|
|
{market.BreakoutLong, BreakoutActionCloseAll},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(string(tt.level), func(t *testing.T) {
|
|
action := getBreakoutAction(tt.level)
|
|
if action != tt.expected {
|
|
t.Errorf("Expected %v, got %v", tt.expected, action)
|
|
}
|
|
})
|
|
}
|
|
}
|