Skip to content

Исправить алгоритм автокурса: GAP, защита от обгона лидера, обработка одинаковых курсов #68

@dapi

Description

@dapi

Описание проблемы

Текущая реализация auto_comission_by_external_comissions в RateComissionCalculator не соответствует бизнес-требованиям.

Бизнес-правила (требуемое поведение)

Занимать наивысшую позицию от позиции X до позиции Y, соблюдая диапазон курса от A до B.
Если в целевом диапазоне все обменники имеют одинаковый курс (мы не можем занять позицию), мы делаем курс на 1 тысячную меньше, при условии что это нас не выкинет из беста (то есть мы не должны обогнать лучший обменник).

Проблемы текущей реализации

Требование Текущий код Статус
GAP = 0.001 (1 тысячная) AUTO_COMISSION_GAP = 0.01 (1 сотая) ❌ Неверно
Не обгонять позицию 1 Не реализовано ❌ Отсутствует
Если все одинаковые → ставим такой же Ставит first - GAP всегда ❌ Неверно

Примеры (Use Cases)

Пример #1 (AS-IS) — текущее поведение ✅

Условие: позиции 2-5, курс 1%-2%

BestChange:
  Поз 1: обменник1 = 1%
  Поз 2: обмен2    = 1.1%
  Поз 3: обменник3 = 2%

Результат: 1.099% (1.1% - 0.001)
Ожидаемая позиция: 2

Пример #2 (TO-BE) — требует доработки ❌

Условие: позиции 2-5, курс 1%-2%

BestChange:
  Поз 1: обменник1 = 0.9%  ← лучший
  Поз 2-7: все по 1%

Текущий результат: 0.99% (неверно)
Ожидаемый результат: 1% (все одинаковые, встаём в очередь)

Пример #3 (TO-BE) — требует доработки ❌

Условие: позиции 2-5, курс 1%-2%

BestChange:
  Поз 1-7: все по 1%

Текущий результат: 0.99% (обгоняем лидера → выкинет из беста!)
Ожидаемый результат: 1% (не обгоняем лидера)

Предлагаемое решение

AUTO_COMISSION_GAP = 0.001  # Изменить с 0.01 на 0.001

def auto_comission_by_external_comissions
  return 0 unless could_be_calculated?

  external_rates_in_target_position = external_rates[(position_from - 1)..(position_to - 1)]
  return autorate_from unless external_rates_in_target_position.present?

  external_rates_in_target_comission = external_rates_in_target_position.select do |rate|
    (autorate_from..autorate_to).include?(rate.target_rate_percent)
  end
  return autorate_from if external_rates_in_target_comission.empty?

  best_in_target = external_rates_in_target_comission.first.target_rate_percent
  best_overall = external_rates.first&.target_rate_percent

  # Проверяем: все ли в целевом диапазоне имеют одинаковый курс?
  all_same = external_rates_in_target_comission.all? { |r| r.target_rate_percent == best_in_target }

  if all_same
    # Все одинаковые — ставим такой же курс
    target_comission = best_in_target
  else
    # Есть разные — ставим чуть лучше
    target_comission = best_in_target - AUTO_COMISSION_GAP
  end

  # НЕ обгоняем лидера (позиция 1)
  if best_overall && target_comission < best_overall
    target_comission = best_in_target
  end

  target_comission
end

Файлы для изменения

  • app/services/gera/rate_comission_calculator.rb

Чеклист

  • Изменить AUTO_COMISSION_GAP с 0.01 на 0.001
  • Добавить проверку "все одинаковые курсы"
  • Добавить защиту от обгона лидера (позиция 1)
  • Написать тесты для всех use cases
  • Обновить документацию

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions