Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions backtest/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,18 +503,19 @@ func (r *Runner) buildDecisionContext(ts int64, marketData map[string]*market.Da

runtime := int((ts - int64(r.cfg.StartTS*1000)) / 60000)
ctx := &decision.Context{
CurrentTime: time.UnixMilli(ts).UTC().Format("2006-01-02 15:04:05 UTC"),
RuntimeMinutes: runtime,
CallCount: callCount,
Account: accountInfo,
Positions: positions,
CandidateCoins: candidateCoins,
PromptVariant: r.cfg.PromptVariant,
MarketDataMap: marketData,
MultiTFMarket: multiTF,
BTCETHLeverage: r.cfg.Leverage.BTCETHLeverage,
AltcoinLeverage: r.cfg.Leverage.AltcoinLeverage,
Timeframes: r.cfg.Timeframes,
CurrentTime: time.UnixMilli(ts).UTC().Format("2006-01-02 15:04:05 UTC"),
CurrentTimestampMs: ts, // Set current backtest timestamp for accurate holding duration calculation
RuntimeMinutes: runtime,
CallCount: callCount,
Account: accountInfo,
Positions: positions,
CandidateCoins: candidateCoins,
PromptVariant: r.cfg.PromptVariant,
MarketDataMap: marketData,
MultiTFMarket: multiTF,
BTCETHLeverage: r.cfg.Leverage.BTCETHLeverage,
AltcoinLeverage: r.cfg.Leverage.AltcoinLeverage,
Timeframes: r.cfg.Timeframes,
}

// Fetch quantitative data if enabled in strategy (uses current data as approximation)
Expand Down Expand Up @@ -847,7 +848,7 @@ func (r *Runner) convertPositions(priceMap map[string]float64) []decision.Positi
UnrealizedPnLPct: 0,
LiquidationPrice: pos.LiquidationPrice,
MarginUsed: pos.Margin,
UpdateTime: time.Now().UnixMilli(),
UpdateTime: pos.OpenTime, // Use position open time instead of current system time
})
}
return list
Expand Down
42 changes: 24 additions & 18 deletions decision/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,24 @@ type RecentOrder struct {

// Context trading context (complete information passed to AI)
type Context struct {
CurrentTime string `json:"current_time"`
RuntimeMinutes int `json:"runtime_minutes"`
CallCount int `json:"call_count"`
Account AccountInfo `json:"account"`
Positions []PositionInfo `json:"positions"`
CandidateCoins []CandidateCoin `json:"candidate_coins"`
PromptVariant string `json:"prompt_variant,omitempty"`
TradingStats *TradingStats `json:"trading_stats,omitempty"`
RecentOrders []RecentOrder `json:"recent_orders,omitempty"`
MarketDataMap map[string]*market.Data `json:"-"`
MultiTFMarket map[string]map[string]*market.Data `json:"-"`
OITopDataMap map[string]*OITopData `json:"-"`
QuantDataMap map[string]*QuantData `json:"-"`
OIRankingData *provider.OIRankingData `json:"-"` // Market-wide OI ranking data
BTCETHLeverage int `json:"-"`
AltcoinLeverage int `json:"-"`
Timeframes []string `json:"-"`
CurrentTime string `json:"current_time"`
CurrentTimestampMs int64 `json:"-"` // Current timestamp in milliseconds (for backtest time calculations)
RuntimeMinutes int `json:"runtime_minutes"`
CallCount int `json:"call_count"`
Account AccountInfo `json:"account"`
Positions []PositionInfo `json:"positions"`
CandidateCoins []CandidateCoin `json:"candidate_coins"`
PromptVariant string `json:"prompt_variant,omitempty"`
TradingStats *TradingStats `json:"trading_stats,omitempty"`
RecentOrders []RecentOrder `json:"recent_orders,omitempty"`
MarketDataMap map[string]*market.Data `json:"-"`
MultiTFMarket map[string]map[string]*market.Data `json:"-"`
OITopDataMap map[string]*OITopData `json:"-"`
QuantDataMap map[string]*QuantData `json:"-"`
OIRankingData *provider.OIRankingData `json:"-"` // Market-wide OI ranking data
BTCETHLeverage int `json:"-"`
AltcoinLeverage int `json:"-"`
Timeframes []string `json:"-"`
}

// Decision AI trading decision
Expand Down Expand Up @@ -1035,7 +1036,12 @@ func (e *StrategyEngine) formatPositionInfo(index int, pos PositionInfo, ctx *Co

holdingDuration := ""
if pos.UpdateTime > 0 {
durationMs := time.Now().UnixMilli() - pos.UpdateTime
// Use context timestamp if available (for backtest), otherwise use system time (for live trading)
currentTimeMs := ctx.CurrentTimestampMs
if currentTimeMs == 0 {
currentTimeMs = time.Now().UnixMilli()
}
durationMs := currentTimeMs - pos.UpdateTime
durationMin := durationMs / (1000 * 60)
if durationMin < 60 {
holdingDuration = fmt.Sprintf(" | Holding Duration %d min", durationMin)
Expand Down