uxname ha revisionato questo gist 2 days ago. Vai alla revisione
1 file changed, 120 insertions, 49 deletions
test ideas.md
| @@ -1,64 +1,135 @@ | |||
| 1 | - | Отличный план. Вы правильно выделили два главных сценария (базовый и копитрейдинг). Чтобы покрытие было полным и гарантировало стабильность системы, я предлагаю дополнить их сценариями на обработку ошибок и граничные случаи. | |
| 1 | + | # 🧪 Test Plan: Backtest Runner Skill (Mastra Agent) | |
| 2 | 2 | ||
| 3 | - | Вот **Топ-5 идей для тестов `backtest-runner`**, отсортированные от базовых к сложным: | |
| 3 | + | **Цель:** Проверить стабильность, корректность загрузки данных и исполнения стратегий в изолированной среде Freqtrade (Docker). | |
| 4 | + | **Тестируемый инструмент:** `runBacktest` | |
| 5 | + | **Зависимости:** Docker, Santiment Data Service, Freqtrade Image. | |
| 4 | 6 | ||
| 5 | - | ### 1. "Smoke Test": Запуск примитивной стратегии (Infrastructure Check) | |
| 6 | - | **Суть:** Проверка всей цепочки без сложной логики. Стратегия должна быть максимально глупой (например, покупать на каждой четной свече и продавать на нечетной). | |
| 7 | - | * **Цель:** Убедиться, что Docker запускается, вольюмы монтируются, конфиг валиден, и Freqtrade в принципе способен завершить работу. | |
| 7 | + | --- | |
| 8 | + | ||
| 9 | + | ## 🛠 Предварительные требования (Prerequisites) | |
| 10 | + | 1. **Environment:** Локально запущенный Docker Desktop. | |
| 11 | + | 2. **Config:** Заполненный `.env` (доступ к SanR/Santiment API). | |
| 12 | + | 3. **State:** В рамках теста в "памяти" агента (или в файловой системе песочницы) должны существовать файлы `strategy.py` и `config.json`. | |
| 13 | + | ||
| 14 | + | --- | |
| 15 | + | ||
| 16 | + | ## 1. Функциональное тестирование: Базовая механика и Даты | |
| 17 | + | ||
| 18 | + | Эти тесты проверяют, что инфраструктура работает, а данные корректно загружаются для разных эпох рынка. | |
| 19 | + | ||
| 20 | + | ### ✅ Тест-кейс 1.1: Исторический прогон (Deep History) | |
| 21 | + | * **Описание:** Запуск простой стратегии на данных 2-3 летней давности. | |
| 22 | + | * **Цель:** Убедиться, что API Santiment отдает архивные данные и Freqtrade корректно их обрабатывает. | |
| 23 | + | * **Входные данные:** | |
| 24 | + | * **Стратегия:** `SimpleStrategy` (покупка RSI < 30, продажа RSI > 70). | |
| 25 | + | * **Пара:** `BTC/USDT:USDT` (Фьючерсы). | |
| 26 | + | * **Таймфрейм:** `1d`. | |
| 27 | + | * **Timerange:** `20210101-20210201` (Январь 2021). | |
| 8 | 28 | * **Ожидаемый результат:** | |
| 9 | - | * Инструмент возвращает `success: true`. | |
| 10 | - | * В логах (`logTail`) присутствует фраза `Backtesting finished`. | |
| 11 | - | * В результатах есть хотя бы одна сделка. | |
| 12 | - | ||
| 13 | - | ### 2. "Data Fetcher Test": Копитрейдинг с реальными данными (SanR Integration) | |
| 14 | - | **Суть:** Тест стратегии, которая импортирует `sdk.py` и запрашивает сигналы для реального пользователя (например, `semaca`) и реальной пары (`BTC/USDT:USDT`). | |
| 15 | - | * **Цель:** Проверить работу `prepareMarketData`. Это самое узкое место. Тест должен убедиться, что: | |
| 16 | - | 1. Система парсит конфиг и находит нужные пары. | |
| 17 | - | 2. Делает запрос к SanR API / Santiment API. | |
| 18 | - | 3. Скачивает JSON-файлы в `market_cache`. | |
| 19 | - | 4. Freqtrade внутри Docker видит эти данные. | |
| 20 | - | * **Ожидаемый результат:** Бэктест проходит успешно, не падает с ошибкой `No data found`. | |
| 21 | - | ||
| 22 | - | ### 3. "The One-Day Edge Case": Граничный случай с датами | |
| 23 | - | **Суть:** Запуск бэктеста, где дата начала равна дате конца (например, `timerange: "20241001-20241001"`). | |
| 24 | - | * **Почему это важно:** В вашем коде (`src/mastra/pro/tools/freqtrade.ts` и `tools.ts`) есть специальная логика, которая расширяет такой диапазон на +1 день. Если это сломается, Freqtrade загрузит 0 свечей и выдаст ошибку. | |
| 25 | - | * **Ожидаемый результат:** Система должна автоматически расширить диапазон до `20241002`, загрузить данные за сутки и провести тест (24 свечи на 1h таймфрейме). | |
| 26 | - | ||
| 27 | - | ### 4. "The Crash Test": Обработка Runtime-ошибки в Python | |
| 28 | - | **Суть:** Подсунуть стратегию с синтаксически верным кодом, но с логической ошибкой, которая вызовет краш во время выполнения (например, деление на ноль в `populate_indicators` или обращение к несуществующей колонке DataFrame). | |
| 29 | - | * **Цель:** Проверить, как `backtest-runner` обрабатывает падение контейнера или Python-исключения. Агент не должен падать сам, он должен вернуть лог с ошибкой. | |
| 29 | + | 1. Инструмент возвращает `success: true`. | |
| 30 | + | 2. В логах нет ошибок `No data found`. | |
| 31 | + | 3. `Total Trades` > 0 (так как волатильность была высокой). | |
| 32 | + | 4. Графики и сделки соответствуют ценам 2021 года (30k-40k$). | |
| 33 | + | ||
| 34 | + | ### ✅ Тест-кейс 1.2: Свежий прогон + Граничный случай (Single Day) | |
| 35 | + | * **Описание:** Запуск теста за "вчера" или за один конкретный день. | |
| 36 | + | * **Цель:** Проверить наличие свежих данных и работу механизма автоматического расширения дат (фикс проблемы "пустого бэктеста"). | |
| 37 | + | * **Входные данные:** | |
| 38 | + | * **Стратегия:** `SimpleStrategy`. | |
| 39 | + | * **Timerange:** `YYYYMMDD-YYYYMMDD` (где дата начала равна дате конца, например `20241201-20241201`). | |
| 30 | 40 | * **Ожидаемый результат:** | |
| 31 | - | * Инструмент возвращает `success: false` (или `true`, но с явным описанием ошибки в логах). | |
| 32 | - | * В `logTail` содержится Python Traceback (например, `ZeroDivisionError`). | |
| 41 | + | 1. Система **автоматически** расширяет диапазон до +1 дня (в логах агента видно предупреждение/фикс). | |
| 42 | + | 2. Freqtrade успешно запускается и прогоняет 24 свечи (для 1h) или 288 (для 5m). | |
| 43 | + | 3. Результат `success: true`. | |
| 44 | + | ||
| 45 | + | --- | |
| 33 | 46 | ||
| 34 | - | ### 5. "Missing Data Handling": Запрос несуществующей пары | |
| 35 | - | **Суть:** В конфиге указать пару, которой не существует на бирже или в Santiment (например, `NONEXISTENTCOIN/USDT:USDT`). | |
| 36 | - | * **Цель:** Проверить валидацию данных до запуска тяжелого Docker-контейнера. | |
| 47 | + | ## 2. Логическое тестирование: Копитрейдинг (Copy Trading) | |
| 48 | + | ||
| 49 | + | Самый важный блок. Проверяем, что сигналы превращаются в реальные сделки. | |
| 50 | + | ||
| 51 | + | ### ✅ Тест-кейс 2.1: Верификация входа в сделку (Signal Execution) | |
| 52 | + | * **Описание:** Проверка стратегии, использующей `sdk.py` для копирования сигналов конкретного трейдера. | |
| 53 | + | * **Подготовка:** Найти в SanR трейдера (например, `semaca` или `brian`), у которого **точно** был сигнал в выбранный период. | |
| 54 | + | * **Входные данные:** | |
| 55 | + | * **Стратегия:** `CopyTradeStrategy`. Логика: | |
| 56 | + | ```python | |
| 57 | + | # Pseudo-code | |
| 58 | + | if signal['direction'] == 'up': return enter_long | |
| 59 | + | if signal['direction'] == 'down': return enter_short | |
| 60 | + | ``` | |
| 61 | + | * **Конфиг:** Включенная пара, по которой был сигнал (например, `ETH/USDT:USDT`). | |
| 62 | + | * **Timerange:** Период, охватывающий этот сигнал. | |
| 37 | 63 | * **Ожидаемый результат:** | |
| 38 | - | * Инструмент должен выбросить ошибку на этапе `prepareMarketData`. | |
| 39 | - | * Ошибка должна быть понятной: "Missing slugs for pairs..." или "Failed to fetch data". | |
| 40 | - | * Docker запускаться **не должен** (экономия ресурсов). | |
| 64 | + | 1. `prepareMarketData` загружает данные для пары. | |
| 65 | + | 2. В логах стратегии (через `logger.info`) видно: "Received signal UP for ETH". | |
| 66 | + | 3. **Критично:** В таблице результатов Freqtrade `Total Trades` >= 1. | |
| 67 | + | 4. Время входа в сделку в отчете совпадает (с точностью до свечи) со временем сигнала в SanR. | |
| 41 | 68 | ||
| 42 | 69 | --- | |
| 43 | 70 | ||
| 44 | - | ### Как это реализовать в коде (Пример для Vitest) | |
| 71 | + | ## 3. Негативное тестирование и Обработка ошибок (Resilience) | |
| 45 | 72 | ||
| 46 | - | Вы можете создать файл `src/mastra/super/skills/backtest-runner/scenarios.spec.ts` и реализовать эти сценарии, используя моки для `exec` (чтобы не ждать реальный докер долго) или реальные интеграционные тесты (как в примере 2). | |
| 73 | + | Проверяем, как система ведет себя при сбоях. | |
| 47 | 74 | ||
| 48 | - | **Пример структуры теста для кейса №1:** | |
| 75 | + | ### ✅ Тест-кейс 3.1: Runtime-ошибка в коде (Crash Test) | |
| 76 | + | * **Описание:** Запуск стратегии с валидным синтаксисом, но ошибкой выполнения. | |
| 77 | + | * **Входные данные:** | |
| 78 | + | * **Стратегия:** В методе `populate_indicators` добавить `x = 1 / 0`. | |
| 79 | + | * **Timerange:** Любой валидный. | |
| 80 | + | * **Ожидаемый результат:** | |
| 81 | + | 1. Агент **не падает**. | |
| 82 | + | 2. Инструмент возвращает `success: false` (или `true` с текстом ошибки, зависит от реализации парсера). | |
| 83 | + | 3. В поле `error` или `logTail` содержится Python Traceback: `ZeroDivisionError: division by zero`. | |
| 84 | + | 4. Пользователю выводится понятное сообщение: "Произошла ошибка в коде стратегии...". | |
| 85 | + | ||
| 86 | + | ### ✅ Тест-кейс 3.2: Отсутствующие рыночные данные (Invalid Pair) | |
| 87 | + | * **Описание:** Попытка запустить тест на несуществующей или делистинговой монете. | |
| 88 | + | * **Входные данные:** | |
| 89 | + | * **Config:** `pair_whitelist: ["SCAMTOKEN/USDT:USDT"]`. | |
| 90 | + | * **Timerange:** Любой. | |
| 91 | + | * **Ожидаемый результат:** | |
| 92 | + | 1. Бэктест **не начинается** (Docker не запускается). | |
| 93 | + | 2. Ошибка отлавливается на этапе `prepareMarketData`. | |
| 94 | + | 3. Сообщение об ошибке: `Missing slugs for pairs...` или `Data fetch failed`. | |
| 95 | + | ||
| 96 | + | --- | |
| 97 | + | ||
| 98 | + | ## 4. Чек-лист для ручного тестирования (Manual QA) | |
| 99 | + | ||
| 100 | + | Если автоматические тесты прошли, тестировщик должен проверить UX в диалоге с агентом: | |
| 101 | + | ||
| 102 | + | 1. [ ] Попросить агента: *"Протестируй стратегию за 2022 год"*. Агент должен сам сконвертировать это в формат `20220101-20221231`. | |
| 103 | + | 2. [ ] Попросить: *"Протестируй за последнюю неделю"*. Проверить, что даты корректны. | |
| 104 | + | 3. [ ] После успешного теста спросить: *"Какой был максимальный просад (drawdown)?"*. Агент должен прочитать это из логов (используя навык `backtest-reporter`). | |
| 105 | + | ||
| 106 | + | --- | |
| 107 | + | ||
| 108 | + | ## Пример кода для запуска Copy Trading теста (для разработчика) | |
| 109 | + | ||
| 110 | + | Этот код можно использовать в `scenarios.spec.ts` для Тест-кейса 2.1: | |
| 49 | 111 | ||
| 50 | 112 | ```typescript | |
| 51 | - | it('Smoke Test: should complete a simple backtest successfully', async () => { | |
| 52 | - | // 1. Подготовка файлов (Strategy + Config) | |
| 53 | - | await writeFile(strategyPath, minimalWorkingStrategy); | |
| 54 | - | await writeFile(configPath, JSON.stringify(validConfig)); | |
| 55 | - | ||
| 56 | - | // 2. Выполнение | |
| 57 | - | const result = await runBacktest.execute({ timerange: '20240101-20240105' }, context); | |
| 58 | - | ||
| 59 | - | // 3. Проверки | |
| 60 | - | expect(result.success).toBe(true); | |
| 61 | - | expect(result.logTail).toContain('Backtesting finished'); | |
| 62 | - | expect(result.logTail).not.toContain('Traceback'); | |
| 113 | + | it('Copy Trading: should open a trade when signal is present', async () => { | |
| 114 | + | // 1. Setup Strategy that mimics Copy Trading logic | |
| 115 | + | const copyStrategy = ` | |
| 116 | + | class Strategy(IStrategy): | |
| 117 | + | def populate_indicators(self, dataframe, metadata): | |
| 118 | + | # MOCK SIGNAL: Force a buy signal on specific date | |
| 119 | + | dataframe['enter_long'] = 0 | |
| 120 | + | dataframe.loc[dataframe['date'] == '2024-01-15 12:00:00+00:00', 'enter_long'] = 1 | |
| 121 | + | return dataframe | |
| 122 | + | # ... rest of required methods | |
| 123 | + | `; | |
| 124 | + | ||
| 125 | + | // 2. Run Test around that date | |
| 126 | + | await setupArtifacts(copyStrategy, 'ETH/USDT:USDT'); | |
| 127 | + | const result = await runBacktest.execute({ timerange: '20240114-20240116' }); | |
| 128 | + | ||
| 129 | + | // 3. Assertions | |
| 130 | + | expect(result.success).toBe(true); | |
| 131 | + | // Проверяем, что сделка реально открылась | |
| 132 | + | expect(result.logTail).toMatch(/Total Trades\s+\|\s+1/); | |
| 133 | + | expect(result.logTail).toMatch(/Win Rate\s+\|\s+100%|0%/); // Сделка должна быть закрыта | |
| 63 | 134 | }); | |
| 64 | 135 | ``` | |
uxname ha revisionato questo gist 2 days ago. Vai alla revisione
1 file changed, 64 insertions
test ideas.md (file creato)
| @@ -0,0 +1,64 @@ | |||
| 1 | + | Отличный план. Вы правильно выделили два главных сценария (базовый и копитрейдинг). Чтобы покрытие было полным и гарантировало стабильность системы, я предлагаю дополнить их сценариями на обработку ошибок и граничные случаи. | |
| 2 | + | ||
| 3 | + | Вот **Топ-5 идей для тестов `backtest-runner`**, отсортированные от базовых к сложным: | |
| 4 | + | ||
| 5 | + | ### 1. "Smoke Test": Запуск примитивной стратегии (Infrastructure Check) | |
| 6 | + | **Суть:** Проверка всей цепочки без сложной логики. Стратегия должна быть максимально глупой (например, покупать на каждой четной свече и продавать на нечетной). | |
| 7 | + | * **Цель:** Убедиться, что Docker запускается, вольюмы монтируются, конфиг валиден, и Freqtrade в принципе способен завершить работу. | |
| 8 | + | * **Ожидаемый результат:** | |
| 9 | + | * Инструмент возвращает `success: true`. | |
| 10 | + | * В логах (`logTail`) присутствует фраза `Backtesting finished`. | |
| 11 | + | * В результатах есть хотя бы одна сделка. | |
| 12 | + | ||
| 13 | + | ### 2. "Data Fetcher Test": Копитрейдинг с реальными данными (SanR Integration) | |
| 14 | + | **Суть:** Тест стратегии, которая импортирует `sdk.py` и запрашивает сигналы для реального пользователя (например, `semaca`) и реальной пары (`BTC/USDT:USDT`). | |
| 15 | + | * **Цель:** Проверить работу `prepareMarketData`. Это самое узкое место. Тест должен убедиться, что: | |
| 16 | + | 1. Система парсит конфиг и находит нужные пары. | |
| 17 | + | 2. Делает запрос к SanR API / Santiment API. | |
| 18 | + | 3. Скачивает JSON-файлы в `market_cache`. | |
| 19 | + | 4. Freqtrade внутри Docker видит эти данные. | |
| 20 | + | * **Ожидаемый результат:** Бэктест проходит успешно, не падает с ошибкой `No data found`. | |
| 21 | + | ||
| 22 | + | ### 3. "The One-Day Edge Case": Граничный случай с датами | |
| 23 | + | **Суть:** Запуск бэктеста, где дата начала равна дате конца (например, `timerange: "20241001-20241001"`). | |
| 24 | + | * **Почему это важно:** В вашем коде (`src/mastra/pro/tools/freqtrade.ts` и `tools.ts`) есть специальная логика, которая расширяет такой диапазон на +1 день. Если это сломается, Freqtrade загрузит 0 свечей и выдаст ошибку. | |
| 25 | + | * **Ожидаемый результат:** Система должна автоматически расширить диапазон до `20241002`, загрузить данные за сутки и провести тест (24 свечи на 1h таймфрейме). | |
| 26 | + | ||
| 27 | + | ### 4. "The Crash Test": Обработка Runtime-ошибки в Python | |
| 28 | + | **Суть:** Подсунуть стратегию с синтаксически верным кодом, но с логической ошибкой, которая вызовет краш во время выполнения (например, деление на ноль в `populate_indicators` или обращение к несуществующей колонке DataFrame). | |
| 29 | + | * **Цель:** Проверить, как `backtest-runner` обрабатывает падение контейнера или Python-исключения. Агент не должен падать сам, он должен вернуть лог с ошибкой. | |
| 30 | + | * **Ожидаемый результат:** | |
| 31 | + | * Инструмент возвращает `success: false` (или `true`, но с явным описанием ошибки в логах). | |
| 32 | + | * В `logTail` содержится Python Traceback (например, `ZeroDivisionError`). | |
| 33 | + | ||
| 34 | + | ### 5. "Missing Data Handling": Запрос несуществующей пары | |
| 35 | + | **Суть:** В конфиге указать пару, которой не существует на бирже или в Santiment (например, `NONEXISTENTCOIN/USDT:USDT`). | |
| 36 | + | * **Цель:** Проверить валидацию данных до запуска тяжелого Docker-контейнера. | |
| 37 | + | * **Ожидаемый результат:** | |
| 38 | + | * Инструмент должен выбросить ошибку на этапе `prepareMarketData`. | |
| 39 | + | * Ошибка должна быть понятной: "Missing slugs for pairs..." или "Failed to fetch data". | |
| 40 | + | * Docker запускаться **не должен** (экономия ресурсов). | |
| 41 | + | ||
| 42 | + | --- | |
| 43 | + | ||
| 44 | + | ### Как это реализовать в коде (Пример для Vitest) | |
| 45 | + | ||
| 46 | + | Вы можете создать файл `src/mastra/super/skills/backtest-runner/scenarios.spec.ts` и реализовать эти сценарии, используя моки для `exec` (чтобы не ждать реальный докер долго) или реальные интеграционные тесты (как в примере 2). | |
| 47 | + | ||
| 48 | + | **Пример структуры теста для кейса №1:** | |
| 49 | + | ||
| 50 | + | ```typescript | |
| 51 | + | it('Smoke Test: should complete a simple backtest successfully', async () => { | |
| 52 | + | // 1. Подготовка файлов (Strategy + Config) | |
| 53 | + | await writeFile(strategyPath, minimalWorkingStrategy); | |
| 54 | + | await writeFile(configPath, JSON.stringify(validConfig)); | |
| 55 | + | ||
| 56 | + | // 2. Выполнение | |
| 57 | + | const result = await runBacktest.execute({ timerange: '20240101-20240105' }, context); | |
| 58 | + | ||
| 59 | + | // 3. Проверки | |
| 60 | + | expect(result.success).toBe(true); | |
| 61 | + | expect(result.logTail).toContain('Backtesting finished'); | |
| 62 | + | expect(result.logTail).not.toContain('Traceback'); | |
| 63 | + | }); | |
| 64 | + | ``` | |