refactor: rename decision package to kernel

This commit is contained in:
tinkle-community
2026-01-03 14:25:40 +08:00
parent d664dcca3d
commit 13fda47151
13 changed files with 76 additions and 76 deletions
+6 -6
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"nofx/decision"
"nofx/kernel"
"nofx/logger"
"nofx/market"
"nofx/mcp"
@@ -397,7 +397,7 @@ func (s *Server) handlePreviewPrompt(c *gin.Context) {
}
// Create strategy engine to build prompt
engine := decision.NewStrategyEngine(&req.Config)
engine := kernel.NewStrategyEngine(&req.Config)
// Build system prompt (using built-in method from strategy engine)
systemPrompt := engine.BuildSystemPrompt(
@@ -443,7 +443,7 @@ func (s *Server) handleStrategyTestRun(c *gin.Context) {
}
// Create strategy engine to build prompt
engine := decision.NewStrategyEngine(&req.Config)
engine := kernel.NewStrategyEngine(&req.Config)
// Get candidate coins
candidates, err := engine.GetCandidateCoins()
@@ -505,11 +505,11 @@ func (s *Server) handleStrategyTestRun(c *gin.Context) {
oiRankingData := engine.FetchOIRankingData()
// Build real context (for generating User Prompt)
testContext := &decision.Context{
testContext := &kernel.Context{
CurrentTime: time.Now().UTC().Format("2006-01-02 15:04:05 UTC"),
RuntimeMinutes: 0,
CallCount: 1,
Account: decision.AccountInfo{
Account: kernel.AccountInfo{
TotalEquity: 1000.0,
AvailableBalance: 1000.0,
UnrealizedPnL: 0,
@@ -519,7 +519,7 @@ func (s *Server) handleStrategyTestRun(c *gin.Context) {
MarginUsedPct: 0,
PositionCount: 0,
},
Positions: []decision.PositionInfo{},
Positions: []kernel.PositionInfo{},
CandidateCoins: candidates,
PromptVariant: req.PromptVariant,
MarketDataMap: marketDataMap,
+10 -10
View File
@@ -9,7 +9,7 @@ import (
"path/filepath"
"sync"
"nofx/decision"
"nofx/kernel"
"nofx/market"
)
@@ -17,7 +17,7 @@ type cachedDecision struct {
Key string `json:"key"`
PromptVariant string `json:"prompt_variant"`
Timestamp int64 `json:"ts"`
Decision *decision.FullDecision `json:"decision"`
Decision *kernel.FullDecision `json:"decision"`
}
// AICache persists AI decisions for repeated backtesting or replay.
@@ -67,7 +67,7 @@ func (c *AICache) Path() string {
return c.path
}
func (c *AICache) Get(key string) (*decision.FullDecision, bool) {
func (c *AICache) Get(key string) (*kernel.FullDecision, bool) {
if c == nil || key == "" {
return nil, false
}
@@ -80,7 +80,7 @@ func (c *AICache) Get(key string) (*decision.FullDecision, bool) {
return cloneDecision(entry.Decision), true
}
func (c *AICache) Put(key string, variant string, ts int64, decision *decision.FullDecision) error {
func (c *AICache) Put(key string, variant string, ts int64, decision *kernel.FullDecision) error {
if c == nil || key == "" || decision == nil {
return nil
}
@@ -109,7 +109,7 @@ func (c *AICache) save() error {
return writeFileAtomic(c.path, data, 0o644)
}
func cloneDecision(src *decision.FullDecision) *decision.FullDecision {
func cloneDecision(src *kernel.FullDecision) *kernel.FullDecision {
if src == nil {
return nil
}
@@ -117,14 +117,14 @@ func cloneDecision(src *decision.FullDecision) *decision.FullDecision {
if err != nil {
return nil
}
var dst decision.FullDecision
var dst kernel.FullDecision
if err := json.Unmarshal(data, &dst); err != nil {
return nil
}
return &dst
}
func computeCacheKey(ctx *decision.Context, variant string, ts int64) (string, error) {
func computeCacheKey(ctx *kernel.Context, variant string, ts int64) (string, error) {
if ctx == nil {
return "", fmt.Errorf("context is nil")
}
@@ -132,9 +132,9 @@ func computeCacheKey(ctx *decision.Context, variant string, ts int64) (string, e
Variant string `json:"variant"`
Timestamp int64 `json:"ts"`
CurrentTime string `json:"current_time"`
Account decision.AccountInfo `json:"account"`
Positions []decision.PositionInfo `json:"positions"`
CandidateCoins []decision.CandidateCoin `json:"candidate_coins"`
Account kernel.AccountInfo `json:"account"`
Positions []kernel.PositionInfo `json:"positions"`
CandidateCoins []kernel.CandidateCoin `json:"candidate_coins"`
MarketData map[string]market.Data `json:"market"`
MarginUsedPct float64 `json:"margin_used_pct"`
Runtime int `json:"runtime_minutes"`
+20 -20
View File
@@ -13,7 +13,7 @@ import (
"sync"
"time"
"nofx/decision"
"nofx/kernel"
"nofx/market"
"nofx/mcp"
"nofx/store"
@@ -34,7 +34,7 @@ type Runner struct {
cfg BacktestConfig
feed *DataFeed
account *BacktestAccount
strategyEngine *decision.StrategyEngine
strategyEngine *kernel.StrategyEngine
decisionLogDir string
mcpClient mcp.AIClient
@@ -118,7 +118,7 @@ func NewRunner(cfg BacktestConfig, mcpClient mcp.AIClient) (*Runner, error) {
// Create strategy engine from backtest config for unified prompt generation
strategyConfig := cfg.ToStrategyConfig()
strategyEngine := decision.NewStrategyEngine(strategyConfig)
strategyEngine := kernel.NewStrategyEngine(strategyConfig)
r := &Runner{
cfg: cfg,
@@ -305,7 +305,7 @@ func (r *Runner) stepOnce() error {
record = rec
var (
fullDecision *decision.FullDecision
fullDecision *kernel.FullDecision
fromCache bool
cacheKey string
)
@@ -470,7 +470,7 @@ func (r *Runner) stepOnce() error {
return nil
}
func (r *Runner) buildDecisionContext(ts int64, marketData map[string]*market.Data, multiTF map[string]map[string]*market.Data, priceMap map[string]float64, callCount int) (*decision.Context, *store.DecisionRecord, error) {
func (r *Runner) buildDecisionContext(ts int64, marketData map[string]*market.Data, multiTF map[string]map[string]*market.Data, priceMap map[string]float64, callCount int) (*kernel.Context, *store.DecisionRecord, error) {
equity, unrealized, _ := r.account.TotalEquity(priceMap)
available := r.account.Cash()
marginUsed := r.totalMarginUsed()
@@ -479,7 +479,7 @@ func (r *Runner) buildDecisionContext(ts int64, marketData map[string]*market.Da
marginPct = (marginUsed / equity) * 100
}
accountInfo := decision.AccountInfo{
accountInfo := kernel.AccountInfo{
TotalEquity: equity,
AvailableBalance: available,
TotalPnL: equity - r.account.InitialBalance(),
@@ -495,14 +495,14 @@ func (r *Runner) buildDecisionContext(ts int64, marketData map[string]*market.Da
candidateCoins, err := r.strategyEngine.GetCandidateCoins()
if err != nil {
// Fallback to simple list if strategy engine fails
candidateCoins = make([]decision.CandidateCoin, 0, len(r.cfg.Symbols))
candidateCoins = make([]kernel.CandidateCoin, 0, len(r.cfg.Symbols))
for _, sym := range r.cfg.Symbols {
candidateCoins = append(candidateCoins, decision.CandidateCoin{Symbol: sym, Sources: []string{"backtest"}})
candidateCoins = append(candidateCoins, kernel.CandidateCoin{Symbol: sym, Sources: []string{"backtest"}})
}
}
runtime := int((ts - int64(r.cfg.StartTS*1000)) / 60000)
ctx := &decision.Context{
ctx := &kernel.Context{
CurrentTime: time.UnixMilli(ts).UTC().Format("2006-01-02 15:04:05 UTC"),
RuntimeMinutes: runtime,
CallCount: callCount,
@@ -566,7 +566,7 @@ func (r *Runner) buildDecisionContext(ts int64, marketData map[string]*market.Da
return ctx, record, nil
}
func (r *Runner) fillDecisionRecord(record *store.DecisionRecord, full *decision.FullDecision) {
func (r *Runner) fillDecisionRecord(record *store.DecisionRecord, full *kernel.FullDecision) {
record.InputPrompt = full.UserPrompt
record.CoTTrace = full.CoTTrace
if len(full.Decisions) > 0 {
@@ -576,12 +576,12 @@ func (r *Runner) fillDecisionRecord(record *store.DecisionRecord, full *decision
}
}
func (r *Runner) invokeAIWithRetry(ctx *decision.Context) (*decision.FullDecision, error) {
func (r *Runner) invokeAIWithRetry(ctx *kernel.Context) (*kernel.FullDecision, error) {
var lastErr error
for attempt := 0; attempt < aiDecisionMaxRetries; attempt++ {
// Use GetFullDecisionWithStrategy with the pre-configured strategy engine
// This ensures backtest uses the same unified prompt generation as live trading
fd, err := decision.GetFullDecisionWithStrategy(
fd, err := kernel.GetFullDecisionWithStrategy(
ctx,
r.mcpClient,
r.strategyEngine,
@@ -597,7 +597,7 @@ func (r *Runner) invokeAIWithRetry(ctx *decision.Context) (*decision.FullDecisio
return nil, lastErr
}
func (r *Runner) executeDecision(dec decision.Decision, priceMap map[string]float64, ts int64, cycle int) (store.DecisionAction, []TradeEvent, string, error) {
func (r *Runner) executeDecision(dec kernel.Decision, priceMap map[string]float64, ts int64, cycle int) (store.DecisionAction, []TradeEvent, string, error) {
symbol := dec.Symbol
usedLeverage := r.resolveLeverage(dec.Leverage, symbol)
actionRecord := store.DecisionAction{
@@ -739,7 +739,7 @@ func (r *Runner) executeDecision(dec decision.Decision, priceMap map[string]floa
}
}
func (r *Runner) determineQuantity(dec decision.Decision, price float64) float64 {
func (r *Runner) determineQuantity(dec kernel.Decision, price float64) float64 {
snapshot := r.snapshotState()
equity := snapshot.Equity
if equity <= 0 {
@@ -777,7 +777,7 @@ func (r *Runner) determineQuantity(dec decision.Decision, price float64) float64
return qty
}
func (r *Runner) determineCloseQuantity(symbol, side string, dec decision.Decision) float64 {
func (r *Runner) determineCloseQuantity(symbol, side string, dec kernel.Decision) float64 {
for _, pos := range r.account.Positions() {
if pos.Symbol == strings.ToUpper(symbol) && pos.Side == side {
return pos.Quantity
@@ -831,12 +831,12 @@ func (r *Runner) snapshotPositions(priceMap map[string]float64) []store.Position
return list
}
func (r *Runner) convertPositions(priceMap map[string]float64) []decision.PositionInfo {
func (r *Runner) convertPositions(priceMap map[string]float64) []kernel.PositionInfo {
positions := r.account.Positions()
list := make([]decision.PositionInfo, 0, len(positions))
list := make([]kernel.PositionInfo, 0, len(positions))
for _, pos := range positions {
price := priceMap[pos.Symbol]
list = append(list, decision.PositionInfo{
list = append(list, kernel.PositionInfo{
Symbol: pos.Symbol,
Side: pos.Side,
EntryPrice: pos.EntryPrice,
@@ -1416,7 +1416,7 @@ func snapshotsToMap(snaps []PositionSnapshot) map[string]PositionSnapshot {
return positions
}
func sortDecisionsByPriority(decisions []decision.Decision) []decision.Decision {
func sortDecisionsByPriority(decisions []kernel.Decision) []kernel.Decision {
if len(decisions) <= 1 {
return decisions
}
@@ -1434,7 +1434,7 @@ func sortDecisionsByPriority(decisions []decision.Decision) []decision.Decision
}
}
result := make([]decision.Decision, len(decisions))
result := make([]kernel.Decision, len(decisions))
copy(result, decisions)
sort.Slice(result, func(i, j int) bool {
+9 -9
View File
@@ -9,7 +9,7 @@ import (
"sync"
"time"
"nofx/decision"
"nofx/kernel"
"nofx/logger"
"nofx/market"
"nofx/mcp"
@@ -18,7 +18,7 @@ import (
// TraderExecutor interface for executing trades
type TraderExecutor interface {
ExecuteDecision(decision *decision.Decision) error
ExecuteDecision(decision *kernel.Decision) error
GetBalance() (map[string]interface{}, error)
}
@@ -166,7 +166,7 @@ func (e *DebateEngine) runDebate(session *store.DebateSessionWithDetails, strate
}()
// Create strategy engine for building context
strategyEngine := decision.NewStrategyEngine(strategyConfig)
strategyEngine := kernel.NewStrategyEngine(strategyConfig)
// Build market context using strategy config
ctx, err := e.buildMarketContext(session, strategyEngine)
@@ -289,7 +289,7 @@ func (e *DebateEngine) runDebate(session *store.DebateSessionWithDetails, strate
}
// buildMarketContext builds the market context using strategy engine
func (e *DebateEngine) buildMarketContext(session *store.DebateSessionWithDetails, strategyEngine *decision.StrategyEngine) (*decision.Context, error) {
func (e *DebateEngine) buildMarketContext(session *store.DebateSessionWithDetails, strategyEngine *kernel.StrategyEngine) (*kernel.Context, error) {
config := strategyEngine.GetConfig()
// Get candidate coins
@@ -336,11 +336,11 @@ func (e *DebateEngine) buildMarketContext(session *store.DebateSessionWithDetail
oiRankingData := strategyEngine.FetchOIRankingData()
// Build context
ctx := &decision.Context{
ctx := &kernel.Context{
CurrentTime: time.Now().UTC().Format("2006-01-02 15:04:05 UTC"),
RuntimeMinutes: 0,
CallCount: 1,
Account: decision.AccountInfo{
Account: kernel.AccountInfo{
TotalEquity: 1000.0, // Simulated for debate
AvailableBalance: 1000.0,
UnrealizedPnL: 0,
@@ -350,7 +350,7 @@ func (e *DebateEngine) buildMarketContext(session *store.DebateSessionWithDetail
MarginUsedPct: 0,
PositionCount: 0,
},
Positions: []decision.PositionInfo{},
Positions: []kernel.PositionInfo{},
CandidateCoins: candidates,
PromptVariant: session.PromptVariant,
MarketDataMap: marketDataMap,
@@ -539,7 +539,7 @@ func (e *DebateEngine) getParticipantResponse(
}
// collectVotes collects final votes from all participants
func (e *DebateEngine) collectVotes(session *store.DebateSessionWithDetails, strategyEngine *decision.StrategyEngine, allMessages []*store.DebateMessage) ([]*store.DebateVote, error) {
func (e *DebateEngine) collectVotes(session *store.DebateSessionWithDetails, strategyEngine *kernel.StrategyEngine, allMessages []*store.DebateMessage) ([]*store.DebateVote, error) {
var votes []*store.DebateVote
// Build voting context
@@ -1009,7 +1009,7 @@ func (e *DebateEngine) ExecuteConsensus(sessionID string, executor TraderExecuto
}
// Create decision
tradeDecision := &decision.Decision{
tradeDecision := &kernel.Decision{
Symbol: session.Symbol,
Action: action,
Leverage: session.FinalDecision.Leverage,
+1 -1
View File
@@ -1,4 +1,4 @@
package decision
package kernel
import (
"encoding/json"
@@ -1,4 +1,4 @@
package decision
package kernel
import (
"fmt"
@@ -1,4 +1,4 @@
package decision
package kernel
import (
"encoding/json"
@@ -1,4 +1,4 @@
package decision
package kernel
import (
"strings"
+1 -1
View File
@@ -1,4 +1,4 @@
package decision
package kernel
import "fmt"
@@ -1,4 +1,4 @@
package decision
package kernel
import (
"strings"
@@ -1,4 +1,4 @@
package decision
package kernel
import (
"testing"
+2 -2
View File
@@ -4,7 +4,7 @@ import (
"context"
"fmt"
"nofx/debate"
"nofx/decision"
"nofx/kernel"
"nofx/logger"
"nofx/store"
"nofx/trader"
@@ -19,7 +19,7 @@ type TraderExecutorAdapter struct {
}
// ExecuteDecision executes a trading decision
func (a *TraderExecutorAdapter) ExecuteDecision(d *decision.Decision) error {
func (a *TraderExecutorAdapter) ExecuteDecision(d *kernel.Decision) error {
return a.autoTrader.ExecuteDecision(d)
}
+22 -22
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"math"
"nofx/decision"
"nofx/kernel"
"nofx/experience"
"nofx/logger"
"nofx/market"
@@ -104,7 +104,7 @@ type AutoTrader struct {
trader Trader // Use Trader interface (supports multiple platforms)
mcpClient mcp.AIClient
store *store.Store // Data storage (decision records, etc.)
strategyEngine *decision.StrategyEngine // Strategy engine (uses strategy configuration)
strategyEngine *kernel.StrategyEngine // Strategy engine (uses strategy configuration)
cycleNumber int // Current cycle number
initialBalance float64
dailyPnL float64
@@ -310,7 +310,7 @@ func NewAutoTrader(config AutoTraderConfig, st *store.Store, userID string) (*Au
if config.StrategyConfig == nil {
return nil, fmt.Errorf("[%s] strategy not configured", config.Name)
}
strategyEngine := decision.NewStrategyEngine(config.StrategyConfig)
strategyEngine := kernel.NewStrategyEngine(config.StrategyConfig)
logger.Infof("✓ [%s] Using strategy engine (strategy configuration loaded)", config.Name)
return &AutoTrader{
@@ -524,7 +524,7 @@ func (at *AutoTrader) runCycle() error {
// 5. Use strategy engine to call AI for decision
logger.Infof("🤖 Requesting AI analysis and decision... [Strategy Engine]")
aiDecision, err := decision.GetFullDecisionWithStrategy(ctx, at.mcpClient, at.strategyEngine, "balanced")
aiDecision, err := kernel.GetFullDecisionWithStrategy(ctx, at.mcpClient, at.strategyEngine, "balanced")
if aiDecision != nil && aiDecision.AIRequestDurationMs > 0 {
record.AIRequestDurationMs = aiDecision.AIRequestDurationMs
@@ -585,8 +585,8 @@ func (at *AutoTrader) runCycle() error {
// logger.Infof(strings.Repeat("-", 70) + "\n")
// 7. Print AI decisions
// logger.Infof("📋 AI decision list (%d items):\n", len(decision.Decisions))
// for i, d := range decision.Decisions {
// logger.Infof("📋 AI decision list (%d items):\n", len(kernel.Decisions))
// for i, d := range kernel.Decisions {
// logger.Infof(" [%d] %s: %s - %s", i+1, d.Symbol, d.Action, d.Reasoning)
// if d.Action == "open_long" || d.Action == "open_short" {
// logger.Infof(" Leverage: %dx | Position: %.2f USDT | Stop loss: %.4f | Take profit: %.4f",
@@ -664,7 +664,7 @@ func (at *AutoTrader) runCycle() error {
}
// buildTradingContext builds trading context
func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
func (at *AutoTrader) buildTradingContext() (*kernel.Context, error) {
// 1. Get account information
balance, err := at.trader.GetBalance()
if err != nil {
@@ -701,7 +701,7 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
return nil, fmt.Errorf("failed to get positions: %w", err)
}
var positionInfos []decision.PositionInfo
var positionInfos []kernel.PositionInfo
totalMarginUsed := 0.0
// Current position key set (for cleaning up closed position records)
@@ -768,7 +768,7 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
peakPnlPct := at.peakPnLCache[posKey]
at.peakPnLCacheMutex.RUnlock()
positionInfos = append(positionInfos, decision.PositionInfo{
positionInfos = append(positionInfos, kernel.PositionInfo{
Symbol: symbol,
Side: side,
EntryPrice: entryPrice,
@@ -820,13 +820,13 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
logger.Infof("📋 [%s] Strategy leverage config: BTC/ETH=%dx, Altcoin=%dx", at.name, btcEthLeverage, altcoinLeverage)
// 6. Build context
ctx := &decision.Context{
ctx := &kernel.Context{
CurrentTime: time.Now().UTC().Format("2006-01-02 15:04:05 UTC"),
RuntimeMinutes: int(time.Since(at.startTime).Minutes()),
CallCount: at.callCount,
BTCETHLeverage: btcEthLeverage,
AltcoinLeverage: altcoinLeverage,
Account: decision.AccountInfo{
Account: kernel.AccountInfo{
TotalEquity: totalEquity,
AvailableBalance: availableBalance,
UnrealizedPnL: totalUnrealizedProfit,
@@ -859,7 +859,7 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
exitTimeStr = time.Unix(trade.ExitTime, 0).UTC().Format("01-02 15:04 UTC")
}
ctx.RecentOrders = append(ctx.RecentOrders, decision.RecentOrder{
ctx.RecentOrders = append(ctx.RecentOrders, kernel.RecentOrder{
Symbol: trade.Symbol,
Side: trade.Side,
EntryPrice: trade.EntryPrice,
@@ -881,7 +881,7 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
} else if stats.TotalTrades == 0 {
logger.Infof("⚠️ [%s] GetFullStats returned 0 trades (traderID=%s)", at.name, at.id)
} else {
ctx.TradingStats = &decision.TradingStats{
ctx.TradingStats = &kernel.TradingStats{
TotalTrades: stats.TotalTrades,
WinRate: stats.WinRate,
ProfitFactor: stats.ProfitFactor,
@@ -933,7 +933,7 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
}
// executeDecisionWithRecord executes AI decision and records detailed information
func (at *AutoTrader) executeDecisionWithRecord(decision *decision.Decision, actionRecord *store.DecisionAction) error {
func (at *AutoTrader) executeDecisionWithRecord(decision *kernel.Decision, actionRecord *store.DecisionAction) error {
switch decision.Action {
case "open_long":
return at.executeOpenLongWithRecord(decision, actionRecord)
@@ -953,7 +953,7 @@ func (at *AutoTrader) executeDecisionWithRecord(decision *decision.Decision, act
// ExecuteDecision executes a trading decision from external sources (e.g., debate consensus)
// This is a public method that can be called by other modules
func (at *AutoTrader) ExecuteDecision(d *decision.Decision) error {
func (at *AutoTrader) ExecuteDecision(d *kernel.Decision) error {
logger.Infof("[%s] Executing external decision: %s %s", at.name, d.Action, d.Symbol)
// Create a minimal action record for tracking
@@ -979,7 +979,7 @@ func (at *AutoTrader) ExecuteDecision(d *decision.Decision) error {
}
// executeOpenLongWithRecord executes open long position and records detailed information
func (at *AutoTrader) executeOpenLongWithRecord(decision *decision.Decision, actionRecord *store.DecisionAction) error {
func (at *AutoTrader) executeOpenLongWithRecord(decision *kernel.Decision, actionRecord *store.DecisionAction) error {
logger.Infof(" 📈 Open long: %s", decision.Symbol)
// ⚠️ Get current positions for multiple checks
@@ -1096,7 +1096,7 @@ func (at *AutoTrader) executeOpenLongWithRecord(decision *decision.Decision, act
}
// executeOpenShortWithRecord executes open short position and records detailed information
func (at *AutoTrader) executeOpenShortWithRecord(decision *decision.Decision, actionRecord *store.DecisionAction) error {
func (at *AutoTrader) executeOpenShortWithRecord(decision *kernel.Decision, actionRecord *store.DecisionAction) error {
logger.Infof(" 📉 Open short: %s", decision.Symbol)
// ⚠️ Get current positions for multiple checks
@@ -1213,7 +1213,7 @@ func (at *AutoTrader) executeOpenShortWithRecord(decision *decision.Decision, ac
}
// executeCloseLongWithRecord executes close long position and records detailed information
func (at *AutoTrader) executeCloseLongWithRecord(decision *decision.Decision, actionRecord *store.DecisionAction) error {
func (at *AutoTrader) executeCloseLongWithRecord(decision *kernel.Decision, actionRecord *store.DecisionAction) error {
logger.Infof(" 🔄 Close long: %s", decision.Symbol)
// Get current price
@@ -1277,7 +1277,7 @@ func (at *AutoTrader) executeCloseLongWithRecord(decision *decision.Decision, ac
}
// executeCloseShortWithRecord executes close short position and records detailed information
func (at *AutoTrader) executeCloseShortWithRecord(decision *decision.Decision, actionRecord *store.DecisionAction) error {
func (at *AutoTrader) executeCloseShortWithRecord(decision *kernel.Decision, actionRecord *store.DecisionAction) error {
logger.Infof(" 🔄 Close short: %s", decision.Symbol)
// Get current price
@@ -1392,7 +1392,7 @@ func (at *AutoTrader) GetSystemPromptTemplate() string {
}
// saveEquitySnapshot saves equity snapshot independently (for drawing profit curve, decoupled from AI decision)
func (at *AutoTrader) saveEquitySnapshot(ctx *decision.Context) {
func (at *AutoTrader) saveEquitySnapshot(ctx *kernel.Context) {
if at.store == nil || ctx == nil {
return
}
@@ -1624,7 +1624,7 @@ func calculatePnLPercentage(unrealizedPnl, marginUsed float64) float64 {
// sortDecisionsByPriority sorts decisions: close positions first, then open positions, finally hold/wait
// This avoids position stacking overflow when changing positions
func sortDecisionsByPriority(decisions []decision.Decision) []decision.Decision {
func sortDecisionsByPriority(decisions []kernel.Decision) []kernel.Decision {
if len(decisions) <= 1 {
return decisions
}
@@ -1644,7 +1644,7 @@ func sortDecisionsByPriority(decisions []decision.Decision) []decision.Decision
}
// Copy decision list
sorted := make([]decision.Decision, len(decisions))
sorted := make([]kernel.Decision, len(decisions))
copy(sorted, decisions)
// Sort by priority