we-promise/sure · error · Provider::TwelveData::InvalidSecurityPriceError

No prices found for security #{symbol} on date #{date}

Error message

No prices found for security #{symbol} on date #{date}

What it means

Provider::TwelveData::InvalidSecurityPriceError raised in fetch_security_price when the underlying fetch_security_prices call for a single-day range (start_date == end_date) succeeded but produced zero usable Price rows. Either values came back empty for that date or every close was nil/<= 0 and got filtered out.

Source

Thrown at app/models/provider/twelve_data.rb:204

      SecurityInfo.new(
        symbol: symbol,
        name: profile.dig("name"),
        links: profile.dig("website"),
        logo_url: logo.dig("url"),
        description: profile.dig("description"),
        kind: profile.dig("type"),
        exchange_operating_mic: exchange_operating_mic
      )
    end
  end

  def fetch_security_price(symbol:, exchange_operating_mic: nil, date:)
    with_provider_response do
      historical_data = fetch_security_prices(symbol:, exchange_operating_mic:, start_date: date, end_date: date)

      raise historical_data.error if historical_data.error.present?
      raise InvalidSecurityPriceError, "No prices found for security #{symbol} on date #{date}" if historical_data.data.blank?

      historical_data.data.first
    end
  end

  def fetch_security_prices(symbol:, exchange_operating_mic: nil, start_date:, end_date:)
    with_provider_response do
      throttle_request
      response = client.get("#{base_url}/time_series") do |req|
        req.params["symbol"] = symbol
        req.params["mic_code"] = exchange_operating_mic
        req.params["start_date"] = start_date.to_s
        req.params["end_date"] = end_date.to_s
        req.params["interval"] = "1day"
      end

      parsed = JSON.parse(response.body)
      check_api_error!(parsed)

View on GitHub (pinned to e69894adb9)

Solutions

  1. Check whether the date is a trading day for that exchange (weekends/holidays have no daily bar)
  2. Widen the window: call fetch_security_prices with start_date a few days earlier and pick the latest bar <= target date, instead of the exact-date helper
  3. Verify the symbol is still valid via search_securities / fetch_security_info; rename mappings go stale
  4. For listing-date issues, confirm the security existed on the requested date

Example fix

// before
price = provider.fetch_security_price(symbol: "AAPL", exchange_operating_mic: "XNAS", date: Date.new(2026, 8, 16)) # Sunday

// after
begin
  price = provider.fetch_security_price(symbol: "AAPL", exchange_operating_mic: "XNAS", date: date)
rescue Provider::TwelveData::InvalidSecurityPriceError
  prices = provider.fetch_security_prices(symbol: "AAPL", exchange_operating_mic: "XNAS", start_date: date - 5.days, end_date: date).data
  price = prices.select { |p| p.date <= date }.max_by(&:date)
end
Defensive patterns

Strategy: fallback

Validate before calling

trading_day = date
trading_day -= 1 while trading_day.wday == 0 || trading_day.wday == 6 # cheap weekend check
price = provider.fetch_security_price(symbol:, exchange_operating_mic:, date: trading_day)

Try / catch

begin
  provider.fetch_security_price(symbol:, exchange_operating_mic:, date:)
rescue Provider::TwelveData::InvalidSecurityPriceError
  prices = provider.fetch_security_prices(symbol:, exchange_operating_mic:, start_date: date - 7.days, end_date: date).data
  prices.select { |p| p.date <= date }.max_by(&:date)
end

Prevention

When it happens

Trigger: Requesting a price for a date the market was closed (weekend/holiday), a date before the security listed, or a delisted symbol; requesting a date in a timezone such that Twelve Data has no daily bar; all closes filtered by the price<=0 guard.

Common situations: Valuing a portfolio 'as of Sunday'; backfilling historical prices before an IPO date; ticker renamed (TWTR → X) so the old symbol has no data.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/4b090f2fb3c5a777. Report an issue: GitHub.