{
  "metric_id": "price-index-paired-yoy",
  "metric_version": 1,
  "month": "2026-09",
  "base_month": "2025-09",
  "frozen_at": "2026-10-12T17:43:40Z",
  "definition": "For each product with at least 20 days of price coverage in both months, we take its median daily price in the month and compare it with its own median daily price in the same month a year earlier; the figure is the median of those per-product changes.",
  "source": "https://memradar.com/price-index/2026-09/",
  "contents": "Segment-level figures only. The paired listings behind them are shown on the source page and are not distributed as a file.",
  "attribution": "MemRadar Memory Price Index, memradar.com/price-index/. These figures are medians computed by MemRadar across products from licensed Keepa price history, not the raw licensed data.",
  "corrections": [],
  "records": {
    "ddr5": {
      "month": "2026-09",
      "base_month": "2025-09",
      "segment": "ddr5",
      "metric_id": "price-index-paired-yoy",
      "metric_version": 1,
      "data_cutoff": "2026-09-30T23:59:59Z",
      "reconstructed": true,
      "frozen_at": "2026-10-12T17:43:40Z",
      "generated_commit": "8b0b8c390",
      "rule": {
        "monthly_price": "carried_forward_daily_median",
        "day_price": "last reading of the UTC day, the semantics of buildDailySeries at scripts/generate-product-pages.js:819-830",
        "carry_cap_days": 90,
        "min_covered_days": 20,
        "covered_days_meaning": "Calendar days that contribute to the carried-forward monthly series after no-offer boundaries and the 90-day carry cap are applied. Not a count of stored observations: before 2026-07-22 the stored history is Keepa change points, so a month with four stored rows is a month whose price moved four times, not a month observed four times.",
        "month_boundary": "UTC",
        "cohort_universe": "all products with history, regardless of present-day page or index state",
        "pair_identity": "the same Amazon ASIN in both months",
        "no_offer_backfill": "Before 2026-07-22 the history is a one-time Keepa load whose csv is a change-point series, so a price_history row with in_stock=false marks the START of a no-offer interval that ends at the next in-stock row, not a single bad day (scripts/backfill-keepa.js:45-61).",
        "no_offer_live": "From 2026-07-22, a successful fetch writes one price_history row per in-stock product and no row at all when the product has no offer (backend/lib/priceFetch.js:190-205), so there are zero in_stock=false rows in the live era. A fetch batch is therefore identified by a distinct price_history.fetched_at value, which the fetch stamps once per run and shares across every row it writes (backend/lib/priceFetch.js:178). A UTC day on which at least one batch exists and on which the product appears in NONE of that day's batches is treated as an observed no-offer day. A day on which the product appears in at least one batch is covered, even if it is absent from another batch the same day. A day with no batch at all is not evidence either way and leaves the carry running. This rule is evaluated from price_history alone and uses no current-state table.",
        "quantile_helper": "percentile(sorted, p) in backend/lib/stats.js, linear interpolation on (n-1)*p/100",
        "median_helper": "median(xs) in backend/lib/stats.js, even n is the mean of the two middle values"
      },
      "n": 61,
      "median": 405.54,
      "p25": 368.36,
      "p75": 450.03,
      "rose_share": 100,
      "loo_low": 402.78,
      "loo_high": 406.45,
      "pair_count": 61,
      "exclusion_counts": {
        "relisting_duplicates": 1,
        "multi_unit": 1,
        "service_bundles": 1
      }
    },
    "ddr4": {
      "month": "2026-09",
      "base_month": "2025-09",
      "segment": "ddr4",
      "metric_id": "price-index-paired-yoy",
      "metric_version": 1,
      "data_cutoff": "2026-09-30T23:59:59Z",
      "reconstructed": true,
      "frozen_at": "2026-10-12T17:43:40Z",
      "generated_commit": "8b0b8c390",
      "rule": {
        "monthly_price": "carried_forward_daily_median",
        "day_price": "last reading of the UTC day, the semantics of buildDailySeries at scripts/generate-product-pages.js:819-830",
        "carry_cap_days": 90,
        "min_covered_days": 20,
        "covered_days_meaning": "Calendar days that contribute to the carried-forward monthly series after no-offer boundaries and the 90-day carry cap are applied. Not a count of stored observations: before 2026-07-22 the stored history is Keepa change points, so a month with four stored rows is a month whose price moved four times, not a month observed four times.",
        "month_boundary": "UTC",
        "cohort_universe": "all products with history, regardless of present-day page or index state",
        "pair_identity": "the same Amazon ASIN in both months",
        "no_offer_backfill": "Before 2026-07-22 the history is a one-time Keepa load whose csv is a change-point series, so a price_history row with in_stock=false marks the START of a no-offer interval that ends at the next in-stock row, not a single bad day (scripts/backfill-keepa.js:45-61).",
        "no_offer_live": "From 2026-07-22, a successful fetch writes one price_history row per in-stock product and no row at all when the product has no offer (backend/lib/priceFetch.js:190-205), so there are zero in_stock=false rows in the live era. A fetch batch is therefore identified by a distinct price_history.fetched_at value, which the fetch stamps once per run and shares across every row it writes (backend/lib/priceFetch.js:178). A UTC day on which at least one batch exists and on which the product appears in NONE of that day's batches is treated as an observed no-offer day. A day on which the product appears in at least one batch is covered, even if it is absent from another batch the same day. A day with no batch at all is not evidence either way and leaves the carry running. This rule is evaluated from price_history alone and uses no current-state table.",
        "quantile_helper": "percentile(sorted, p) in backend/lib/stats.js, linear interpolation on (n-1)*p/100",
        "median_helper": "median(xs) in backend/lib/stats.js, even n is the mean of the two middle values"
      },
      "n": 28,
      "median": 171.72,
      "p25": 159.29,
      "p75": 201.27,
      "rose_share": 100,
      "loo_low": 170.78,
      "loo_high": 172.66,
      "pair_count": 28,
      "exclusion_counts": {
        "relisting_duplicates": 1,
        "multi_unit": 1,
        "service_bundles": 1
      }
    },
    "nvme_ssd": {
      "month": "2026-09",
      "base_month": "2025-09",
      "segment": "nvme_ssd",
      "metric_id": "price-index-paired-yoy",
      "metric_version": 1,
      "data_cutoff": "2026-09-30T23:59:59Z",
      "reconstructed": true,
      "frozen_at": "2026-10-12T17:43:40Z",
      "generated_commit": "8b0b8c390",
      "rule": {
        "monthly_price": "carried_forward_daily_median",
        "day_price": "last reading of the UTC day, the semantics of buildDailySeries at scripts/generate-product-pages.js:819-830",
        "carry_cap_days": 90,
        "min_covered_days": 20,
        "covered_days_meaning": "Calendar days that contribute to the carried-forward monthly series after no-offer boundaries and the 90-day carry cap are applied. Not a count of stored observations: before 2026-07-22 the stored history is Keepa change points, so a month with four stored rows is a month whose price moved four times, not a month observed four times.",
        "month_boundary": "UTC",
        "cohort_universe": "all products with history, regardless of present-day page or index state",
        "pair_identity": "the same Amazon ASIN in both months",
        "no_offer_backfill": "Before 2026-07-22 the history is a one-time Keepa load whose csv is a change-point series, so a price_history row with in_stock=false marks the START of a no-offer interval that ends at the next in-stock row, not a single bad day (scripts/backfill-keepa.js:45-61).",
        "no_offer_live": "From 2026-07-22, a successful fetch writes one price_history row per in-stock product and no row at all when the product has no offer (backend/lib/priceFetch.js:190-205), so there are zero in_stock=false rows in the live era. A fetch batch is therefore identified by a distinct price_history.fetched_at value, which the fetch stamps once per run and shares across every row it writes (backend/lib/priceFetch.js:178). A UTC day on which at least one batch exists and on which the product appears in NONE of that day's batches is treated as an observed no-offer day. A day on which the product appears in at least one batch is covered, even if it is absent from another batch the same day. A day with no batch at all is not evidence either way and leaves the carry running. This rule is evaluated from price_history alone and uses no current-state table.",
        "quantile_helper": "percentile(sorted, p) in backend/lib/stats.js, linear interpolation on (n-1)*p/100",
        "median_helper": "median(xs) in backend/lib/stats.js, even n is the mean of the two middle values"
      },
      "n": 66,
      "median": 151.9,
      "p25": 129.51,
      "p75": 169.56,
      "rose_share": 100,
      "loo_low": 151.07,
      "loo_high": 152.74,
      "pair_count": 66,
      "exclusion_counts": {
        "relisting_duplicates": 1,
        "multi_unit": 1,
        "service_bundles": 1
      }
    },
    "sata_ssd": {
      "month": "2026-09",
      "base_month": "2025-09",
      "segment": "sata_ssd",
      "metric_id": "price-index-paired-yoy",
      "metric_version": 1,
      "data_cutoff": "2026-09-30T23:59:59Z",
      "reconstructed": true,
      "frozen_at": "2026-10-12T17:43:40Z",
      "generated_commit": "8b0b8c390",
      "rule": {
        "monthly_price": "carried_forward_daily_median",
        "day_price": "last reading of the UTC day, the semantics of buildDailySeries at scripts/generate-product-pages.js:819-830",
        "carry_cap_days": 90,
        "min_covered_days": 20,
        "covered_days_meaning": "Calendar days that contribute to the carried-forward monthly series after no-offer boundaries and the 90-day carry cap are applied. Not a count of stored observations: before 2026-07-22 the stored history is Keepa change points, so a month with four stored rows is a month whose price moved four times, not a month observed four times.",
        "month_boundary": "UTC",
        "cohort_universe": "all products with history, regardless of present-day page or index state",
        "pair_identity": "the same Amazon ASIN in both months",
        "no_offer_backfill": "Before 2026-07-22 the history is a one-time Keepa load whose csv is a change-point series, so a price_history row with in_stock=false marks the START of a no-offer interval that ends at the next in-stock row, not a single bad day (scripts/backfill-keepa.js:45-61).",
        "no_offer_live": "From 2026-07-22, a successful fetch writes one price_history row per in-stock product and no row at all when the product has no offer (backend/lib/priceFetch.js:190-205), so there are zero in_stock=false rows in the live era. A fetch batch is therefore identified by a distinct price_history.fetched_at value, which the fetch stamps once per run and shares across every row it writes (backend/lib/priceFetch.js:178). A UTC day on which at least one batch exists and on which the product appears in NONE of that day's batches is treated as an observed no-offer day. A day on which the product appears in at least one batch is covered, even if it is absent from another batch the same day. A day with no batch at all is not evidence either way and leaves the carry running. This rule is evaluated from price_history alone and uses no current-state table.",
        "quantile_helper": "percentile(sorted, p) in backend/lib/stats.js, linear interpolation on (n-1)*p/100",
        "median_helper": "median(xs) in backend/lib/stats.js, even n is the mean of the two middle values"
      },
      "n": 27,
      "median": 155.57,
      "p25": 143.24,
      "p75": 253.58,
      "rose_share": 100,
      "loo_low": 154.47,
      "loo_high": 164.65,
      "pair_count": 27,
      "exclusion_counts": {
        "relisting_duplicates": 1,
        "multi_unit": 1,
        "service_bundles": 1
      }
    }
  }
}
