{"record":{"id":"59a5abd1927d6012","repo":"we-promise/sure","slug":"no-t-invest-price-for-symbol-on-date","errorCode":null,"errorMessage":"No T-Invest price for #{symbol} on #{date}","messagePattern":"No T-Invest price for #(.+?) on #(.+?)","errorType":"exception","errorClass":"Provider::TinkoffInvest::InvalidSecurityPriceError","httpStatus":null,"severity":"warning","filePath":"app/models/provider/tinkoff_invest.rb","lineNumber":124,"sourceCode":"        logo_url: logo_url(detail.dig(\"brand\", \"logoName\")),\n        description: nil,\n        kind: surfaced_kind(short[\"instrumentType\"]),\n        exchange_operating_mic: mic_for(short[\"classCode\"], detail[\"exchange\"])\n      )\n    end\n  end\n\n  def fetch_security_price(symbol:, exchange_operating_mic:, date:)\n    with_provider_response do\n      historical = fetch_security_prices(\n        symbol: symbol,\n        exchange_operating_mic: exchange_operating_mic,\n        start_date: date,\n        end_date: date\n      )\n\n      raise historical.error if historical.error.present?\n      raise InvalidSecurityPriceError, \"No T-Invest price for #{symbol} on #{date}\" if historical.data.blank?\n\n      historical.data.find { |p| p.date == date } ||\n        historical.data.select { |p| p.date <= date }.max_by(&:date) ||\n        historical.data.first\n    end\n  end\n\n  def fetch_security_prices(symbol:, exchange_operating_mic:, start_date:, end_date:)\n    with_provider_response do\n      short = resolve_short(symbol, exchange_operating_mic)\n      raise Error, \"Unknown T-Invest instrument: #{symbol}\" if short.nil?\n\n      uid = short[\"uid\"]\n      bond = short[\"instrumentType\"].to_s == \"bond\"\n      currency = short[\"currency\"].to_s.upcase\n      mic = mic_for(short[\"classCode\"], short[\"exchange\"])\n\n      # Bonds quote in % of par; multiply by nominal to get a money price. A","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/tinkoff_invest.rb#L106-L142","documentation":"fetch_security_price delegates to fetch_security_prices for the single day and raises InvalidSecurityPriceError when the result set is empty -- no candles and no live price existed for that instrument on that date. For T-Invest this typically means a non-trading day (MOEX weekend/holiday), a date before the instrument listed, or a suspended board. The rescue-free raise distinguishes 'we got data but not for this date' from instrument resolution failures.","triggerScenarios":"fetch_security_price(symbol: 'SBER', exchange_operating_mic: 'XMOS', date: <Saturday or MOEX holiday>) returns an empty historical.data; also early-morning calls where the candle feed lags and the live-price append hasn't produced a row for today yet; dates before listing.","commonSituations":"Valuation jobs running on Moscow-exchange holidays not in the app's holiday calendar; 'price as of today' queries fired before session data lands; newly listed bonds with no candle history yet.","solutions":["Validate the date against MOEX trading calendar / walk back to the previous trading day before calling","For 'today' prices, tolerate lag: retry shortly after session open or use the previous close explicitly","Confirm the instrument has any history at all via fetch_security_prices over a wide range"],"exampleFix":"# before\nprice = provider.fetch_security_price(symbol: sym, exchange_operating_mic: mic, date: date)\n\n# after\nbegin\n  price = provider.fetch_security_price(symbol: sym, exchange_operating_mic: mic, date: date)\nrescue Provider::TinkoffInvest::InvalidSecurityPriceError\n  date = MoexTradingCalendar.previous_trading_day(date)\n  retry\nend","handlingStrategy":"fallback","validationCode":"# MOEX trades Mon-Fri; verify holidays before exact-date pricing\ndate = MoexTradingCalendar.previous_trading_day(date) unless MoexTradingCalendar.trading_day?(date)","typeGuard":null,"tryCatchPattern":"begin\n  price = provider.fetch_security_price(symbol:, exchange_operating_mic:, date:)\nrescue Provider::TinkoffInvest::InvalidSecurityPriceError\n  price = security.last_known_price # degrade to previous valuation\nend","preventionTips":["Query ranges and select the wanted date client-side, matching the method's own fallback logic","Avoid 'today' price queries before the session's data lands; schedule valuation after market close"],"tags":["tinkoff-invest","t-invest","price-data","no-data","trading-day"],"backgroundTag":"no-price-data-for-date","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}