Сначала автономный тест остановки, затем торговый бот

AI Trading Ranked

Last Updated: 2026-10-26

Ниже — запускаемый офлайн-пример контрольного контура, а не готовый торговый бот. Он не отправляет заявки, не читает счет и не требует API-ключей. Проверяются незакрытые данные, повторные события и остановка, которая должна сохраняться после перезапуска. Нужна только стандартная библиотека Python.

Разделить обязанности до выбора площадки

Прокрутите таблицу по горизонтали, чтобы увидеть все столбцы. С клавиатуры: перейдите к области таблицы и используйте стрелки.

СлойВход и выходЧто должна выяснить проверка
ДанныеНаблюдения со временемЗакрыта ли свеча, свежа ли она и тот ли это рынок?
СигналВерсия правила и доступные данныеБыл ли сигнал известен до предполагаемой цены исполнения?
РискКапитал, позиции и незавершенные заявкиЧто запрещает новые действия и переживает ли запрет перезапуск?
ИсполнениеНамерение, ID запроса и ответЗаявка отклонена, исполнена, частична или ее состояние неизвестно?
СверкаЗаявки, исполнения и балансыСовпадают ли записи с площадкой после прерывания?

Пример охватывает только часть границы данных и риска. Сигналов и исполнения здесь нет. Пересечение средней не доказывает прибыльность; собственный код сам по себе не создает преимущество.

Запустить воспроизводимый пример

Сохраните код как paper_control.py и выполните python paper_control.py. Демонстрация создает отдельный временный файл с вымышленным состоянием. Ожидаемые статусы: recorded_only, halted, halted; orders_sent всегда равен нулю. После условного пика $1 000 значение $890 включает остановку, которую последующее значение $1 100 не снимает.

"""Offline, single-process teaching fixture. No exchange or order calls."""
import json
from decimal import Decimal, InvalidOperation
from pathlib import Path


def positive(value):
    if isinstance(value, bool):
        raise ValueError("boolean is not a numeric input")
    try:
        number = Decimal(str(value))
    except (InvalidOperation, ValueError):
        raise ValueError("invalid numeric input") from None
    if not number.is_finite() or number <= 0:
        raise ValueError("finite positive number required")
    return number


def inspect(path, sample, now):
    path = Path(path)
    state = json.loads(path.read_text()) if path.exists() else {
        "halted": False, "peak": "1000", "seen": []
    }
    # Corrupt/unknown saved state raises instead of silently resetting the halt.
    if (type(state.get("halted")) is not bool
            or not isinstance(state.get("seen"), list)
            or not all(isinstance(x, str) for x in state["seen"])):
        raise ValueError("invalid saved state")
    peak = positive(state["peak"])
    if state["halted"]:
        return {"status": "halted", "orders_sent": 0}
    stamp = sample.get("closed_at")
    if (type(now) is not int or type(stamp) is not int
            or not 0 <= now - stamp <= 10):
        return {"status": "stale_or_future", "orders_sent": 0}
    if sample.get("closed") is not True:
        return {"status": "bar_not_closed", "orders_sent": 0}
    event = sample.get("event_id")
    if not isinstance(event, str) or not event:
        return {"status": "missing_event_id", "orders_sent": 0}
    if event in state["seen"]:
        return {"status": "duplicate", "orders_sent": 0}
    equity = positive(sample.get("equity"))
    peak = max(peak, equity)
    state["peak"] = str(peak)
    # 10% is a toy boundary, not a recommended account-risk limit.
    state["halted"] = equity <= peak * Decimal("0.9")
    state["seen"].append(event)
    temporary = path.with_name(path.name + ".pending")
    temporary.write_text(json.dumps(state))
    temporary.replace(path)
    # A failed write raises before any accepted result is returned.
    return {"status": "halted" if state["halted"] else "recorded_only",
            "orders_sent": 0}


if __name__ == "__main__":
    import tempfile
    with tempfile.TemporaryDirectory() as folder:
        saved = Path(folder) / "synthetic-state.json"
        base = {"closed": True, "closed_at": 100}
        print(inspect(saved, dict(base, event_id="a", equity="1000"), 101))
        print(inspect(saved, dict(base, event_id="b", equity="890"), 102))
        # A new call reloads the persisted halt even after equity recovers.
        print(inspect(saved, dict(base, event_id="c", equity="1100"), 103))

Десять секунд свежести и граница 10% выбраны для учебного примера. Это не рекомендуемый режим или лимит риска. Следующий вызов заново читает сохраненную остановку. Демонстрационный запуск каждый раз создает новый временный каталог и не затрагивает существующие записи счета.

Проверять отказы, а не только успешный сценарий

Подайте незакрытую свечу, будущую и старую временные метки, затем один ID события дважды. Результат должен называть причину отказа. Нечисловой, бесконечный или неположительный капитал должен вызвать ошибку. Поврежденное сохраненное состояние нельзя молча превращать в новый счет. Ошибка записи файла возникает до сообщения об успешной фиксации решения.

Пример рассчитан на один процесс и одного писателя. Это не транзакционный журнал; рост файла не ограничен, устойчивость к потере питания и конкурирующим записям не установлена. Функции сброса нет. Для реальной системы снятие остановки требует отдельной сверки и записанного решения. Настройка службы Restart=always такого решения не заменяет.

Что еще требуется до интеграции исполнения

Фиксированное число бумажных дней не дает автоматического основания увеличивать капитал. Укажите, каких доказательств работы стратегии, интеграции и эксплуатации еще нет. Хостинг, данные, наблюдение и сопровождение могут требовать времени и денег даже при бесплатном коде. Срок выхода на прибыль здесь не обещается.

Расчеты заявок и потерь разобраны в базовом руководстве. Отдельный бумажный расчет выплат прогнозного рынка проверяет входные данные, не предсказывая исход события.

Учебный инженерный пример, не работающая торговая система, гарантия защиты счета или инвестиционная рекомендация. AITR может получать комиссии по другим коммерческим ссылкам сайта; это не подтверждает качество бота.