============================================================================ Market Data Fetching ============================================================================ fetchMarketDataWithStrategy fetches market data using strategy config (multiple timeframes)
(ctx *Context, engine *StrategyEngine)
| 173 | |
| 174 | // fetchMarketDataWithStrategy fetches market data using strategy config (multiple timeframes) |
| 175 | func fetchMarketDataWithStrategy(ctx *Context, engine *StrategyEngine) error { |
| 176 | config := engine.GetConfig() |
| 177 | ctx.MarketDataMap = make(map[string]*market.Data) |
| 178 | |
| 179 | timeframes := config.Indicators.Klines.SelectedTimeframes |
| 180 | primaryTimeframe := config.Indicators.Klines.PrimaryTimeframe |
| 181 | klineCount := config.Indicators.Klines.PrimaryCount |
| 182 | |
| 183 | // Compatible with old configuration |
| 184 | if len(timeframes) == 0 { |
| 185 | if primaryTimeframe != "" { |
| 186 | timeframes = append(timeframes, primaryTimeframe) |
| 187 | } else { |
| 188 | timeframes = append(timeframes, "3m") |
| 189 | } |
| 190 | if config.Indicators.Klines.LongerTimeframe != "" { |
| 191 | timeframes = append(timeframes, config.Indicators.Klines.LongerTimeframe) |
| 192 | } |
| 193 | } |
| 194 | if primaryTimeframe == "" { |
| 195 | primaryTimeframe = timeframes[0] |
| 196 | } |
| 197 | if klineCount <= 0 { |
| 198 | klineCount = 30 |
| 199 | } |
| 200 | |
| 201 | logger.Infof("📊 Strategy timeframes: %v, Primary: %s, Kline count: %d", timeframes, primaryTimeframe, klineCount) |
| 202 | |
| 203 | // 1. First fetch data for position coins (must fetch) |
| 204 | for _, pos := range ctx.Positions { |
| 205 | data, err := market.GetWithTimeframes(pos.Symbol, timeframes, primaryTimeframe, klineCount) |
| 206 | if err != nil { |
| 207 | logger.Infof("⚠️ Failed to fetch market data for position %s: %v", pos.Symbol, err) |
| 208 | continue |
| 209 | } |
| 210 | ctx.MarketDataMap[pos.Symbol] = data |
| 211 | } |
| 212 | |
| 213 | // 2. Fetch data for all candidate coins |
| 214 | positionSymbols := make(map[string]bool) |
| 215 | for _, pos := range ctx.Positions { |
| 216 | positionSymbols[pos.Symbol] = true |
| 217 | } |
| 218 | |
| 219 | const minOIThresholdMillions = 15.0 // 15M USD minimum open interest value |
| 220 | |
| 221 | for _, coin := range ctx.CandidateCoins { |
| 222 | if _, exists := ctx.MarketDataMap[coin.Symbol]; exists { |
| 223 | continue |
| 224 | } |
| 225 | |
| 226 | data, err := market.GetWithTimeframes(coin.Symbol, timeframes, primaryTimeframe, klineCount) |
| 227 | if err != nil { |
| 228 | logger.Infof("⚠️ Failed to fetch market data for %s: %v", coin.Symbol, err) |
| 229 | continue |
| 230 | } |
| 231 | |
| 232 | // Liquidity filter (skip for xyz dex assets - they don't have OI data from Binance) |
no test coverage detected