Урок 16, последний урок курса "Собери своего арбитражного бота". Бот сканирует рынок, определяет размеры сделок, симулирует исполнения, работает на бумаге и останавливается по лимитам. Сегодня вы сделаете из него то, что другие люди смогут прочитать, запустить и оценить.
Прямой подход
Самый простой способ показать бота: скриншот терминала с зеленым числом или сообщение "на этой неделе он заработал 40 долларов". Скриншот нельзя проверить или повторить, он скрывает все важное: сколько было сделок, насколько велика худшая, какими были настройки, использовались ли реальные деньги.
Релиз отвечает на эти вопросы до того, как их зададут. В нем четыре части: журнал, отчет, README и репозиторий. На каждую уходит меньше часа.
Часть 1: журнал каждого решения
Бот добавляет в файл одну строку на каждую бумажную сделку. Строка является небольшим объектом JSON. Этот формат называют JSON Lines: по одному объекту на строку, его легко дописывать и легко читать обратно. Записывайте не только прибыль: время, пару, размер, цены, действовавшие настройки. То, что вы не записали, потом нельзя объяснить.
Часть 2: отчет, который читает журнал
Небольшой скрипт читает журнал и выводит числа, которые посетитель хочет увидеть первыми: сколько сделок, сколько из них прибыльны, общий итог и худшая отдельная сделка. Худшая сделка важна не меньше общего итога. Затем тот же скрипт записывает веб-страницу.
import json, random, html
random.seed(21)
# 1. the bot appends one line per decision to trades.jsonl (here we fake 12 paper trades)
with open("trades.jsonl", "w") as f:
for i in range(12):
size = round(random.choice([0.5, 1.0]), 1)
profit = round(random.gauss(0.03, 0.12) * size, 4)
f.write(json.dumps({"n": i + 1, "pair": "BTC/USDT", "size": size, "profit": profit}) + "\n")
# 2. the report reads the log and prints the numbers a visitor wants first
trades = [json.loads(line) for line in open("trades.jsonl")]
total = sum(t["profit"] for t in trades)
wins = sum(t["profit"] > 0 for t in trades)
worst = min(t["profit"] for t in trades)
print(f"trades {len(trades)} wins {wins} win rate {wins/len(trades):.0%}")
print(f"total profit {total:+.4f} worst trade {worst:+.4f}")
# 3. the same numbers as a page you can open in a browser or publish
rows = "".join(f"<tr><td>{t['n']}</td><td>{html.escape(t['pair'])}</td><td>{t['size']}</td><td>{t['profit']:+.4f}</td></tr>" for t in trades)
page = f"""<!doctype html><meta charset="utf-8"><title>Paper bot report</title>
<h1>Paper bot report</h1>
<p>Trades: {len(trades)}. Win rate: {wins/len(trades):.0%}. Total profit: {total:+.4f}. Worst trade: {worst:+.4f}.</p>
<p><b>Paper mode: no real money.</b></p>
<table border="1" cellpadding="4"><tr><th>#</th><th>pair</th><th>size</th><th>profit</th></tr>{rows}</table>"""
open("report.html", "w").write(page)
print("wrote report.html,", len(page), "bytes")
Вывод:
trades 12 wins 6 win rate 50%
total profit +0.0432 worst trade -0.2725
wrote report.html, 1088 bytes
Откройте report.html в браузере. Посмотрите на два числа вместе. Половина сделок выиграла, общий итог слегка положителен, но худшая сделка, −0.2725, в шесть раз больше общей прибыли, 0.0432. Одна плохая сделка стирает весь запуск. Одно число, например "profit +0.0432", скрыло бы это. Поэтому отчет выводит худшую сделку рядом с общим итогом.
Искусственные сделки здесь являются случайными числами, они нужны только для того, чтобы скрипту было что читать. В вашем боте журнал поступает с бумажного счета из урока 12.
Часть 3: README
README является первой страницей репозитория. Посетитель читает его десять секунд и решает, продолжать или уйти. Хороший README содержит эти части, в таком порядке:
- Одно предложение: что делает бот. "Бот для бумажной торговли, который ищет ценовые разрывы между двумя биржами".
- Строка статуса: "Бумажный режим. Никаких реальных денег. Не финансовая рекомендация".
- Как запустить: три команды, которые работают на чистой машине, установка, копирование примера конфигурации, запуск.
- Что вы увидите: вывод запуска или ссылку на страницу отчета.
- Как это работает: этапы из урока 3, по одной строке на каждый.
- Известные ограничения: что бумажный счет не моделирует, задержку, других ботов, сбои ног из урока 11. Записать это вызывает больше доверия, чем скрыть.
- Результаты: числа из вашего отчета, с датами и настройками.
Проверьте README как незнакомый человек: откройте новую пустую папку, клонируйте репозиторий, выполните собственные шаги и исправьте каждое место, где застряли.
Часть 4: чистый публичный репозиторий
Перед тем как сделать репозиторий публичным, проверьте следующее. Утекший ключ нельзя вернуть назад.
- Никаких секретов. Ключи, токены и пароли хранятся в переменных окружения или файле, указанном в .gitignore, но никогда не в коде или конфигурации, которую вы коммитите. Вместо этого закоммитьте config.example.json с пустыми или вымышленными значениями.
- Поиск по истории. Если ключ когда-либо попадал в коммит, удаление в новом коммите не убирает его из истории. Создайте новый ключ на бирже, отмените старый и начните публичный репозиторий с чистой истории.
- Файл .gitignore, который исключает журналы, виртуальное окружение и конфигурацию с настоящими значениями.
- Файл лицензии, чтобы люди знали, могут ли они повторно использовать код.
- Небольшие понятные коммиты с сообщениями, которые говорят, что изменилось.
Когда папка готова, используйте команды:
git init
git add .
git status # read this list: no keys, no logs
git commit -m "Paper-trading arbitrage bot: first release"
Создайте пустой репозиторий на используемом хостинге кода, GitHub или GitLab, затем добавьте его адрес как remote и отправьте изменения. Можете попросить агента назвать точные две команды для своего сайта, но перед первой отправкой сами прочитайте git status.
Как говорить о результатах
- Каждый раз говорите "бумажный". Бумажная прибыль является верхней границей, потому что исполнения на настоящем рынке хуже, урок 11.
- Показывайте худшую сделку и число сделок вместе с общим итогом.
- Указывайте даты и настройки. Результат без них нельзя повторить.
- Не считайте короткий удачный запуск доказательством. Двенадцать сделок говорят мало. Сто сделок в разные рыночные дни говорят больше.
- Просите обратную связь конкретно: "Какое предположение в бумажном счете выглядит неправильным?" дает ответы лучше, чем "Что вы думаете?".
Попросите ИИ-агента написать и проверить код
Расплывчатый запрос:
Подготовь моего бота к релизу.
Запрос со встроенными проверками:
Сделай эти шаги и покажи вывод каждого. 1. Найди во всем репозитории, включая историю git, строки, похожие на ключи API или токены, перечисли каждое совпадение, пока ничего не исправляй. 2. Напиши report.py, который читает trades.jsonl, выводит число сделок, выигрыши, общую прибыль и худшую сделку, а также записывает report.html; на примере урока 16 он должен вывести "trades 12 wins 6" и "worst trade -0.2725". 3. Напиши README с семью частями из урока 16 и разделом запуска на чистой машине, выполни команды в новой пустой папке и сообщи, где они не работают. 4. Напиши .gitignore и config.example.json. Не отправляй изменения и не создавай удаленный репозиторий.
Сами прочитайте список из шага 1. Только вы решаете, что считать секретом.
Ваше упражнение
- Запустите код отчета и откройте report.html. Сравните напечатанные строки с уроком.
- Измените seed на 22, затем на 23. Насколько меняются доля побед, общая прибыль и худшая сделка? Что это говорит о показе одного числа из двенадцати сделок?
- Подключите собственного бота: пусть его бумажный счет пишет в trades.jsonl, затем запустите отчет на настоящем бумажном выводе.
- Напишите README и дайте его другу, который никогда не видел проект. Посмотрите, где он застрянет, и исправьте README, а не друга.
- Опубликуйте репозиторий. Отправьте ссылку трем людям и задайте каждому один и тот же конкретный вопрос.
Конец курса и что дальше
Вы начали со сканера, которому требовался час, и заканчиваете ботом, который находит разрывы, проходит стакан, учитывает комиссии и размер, ожидает сбоев, работает на бумаге внутри лимитов, торгует второй стратегией и может быть прочитан и запущен другим человеком. Реальные деньги являются отдельным решением: нужен долгий бумажный запуск, небольшой размер и лимиты риска, которым вы доверяете. Не спешите.
Если вы где-то застряли, в ранних уроках повторяется один и тот же образец: сначала прямой вариант, затем идея, которая его исправляет, затем запрос к агенту со встроенной проверкой. Вернитесь к тому, который вызвал трудности, и повторите упражнение.