BotterのAI活用研究 1.
前回
ロードマップ
Gemini,Claudeと壁打ちしてロードマップを作ってもらいました。それに沿って指示を与えていこうと思っているので、マークダウンとして残しておいてClaude Codeの指示ように保持しておきます。
全体のロードマップは長いので一部抜粋
できるだけ具体的に白黒わかるような達成条件を設定してもらいました。
ちなみにしばらくHyperCoreの開発を行う予定です。
roadmap.md
# 儲かっているウォレット発見システム実装計画
## フェーズ1: 環境構築とデータ収集
**タスク1.1: AWS S3データ取得機能**
**達成条件:**
- [ ] S3からHyperCoreデータダウンロード(サンプルデータレベルの量で問題ない)
- [ ] LZ4圧縮ファイルの正常な解凍
- [ ] 解凍後のデータのプリント出力
**タスク1.2: データのDB化**
**達成条件:**
- [ ] DuckDBにて解凍後データを格納する(サンプルデータレベルの量で問題ない)
- [ ] DuckDBからデータを取得できるようにする
**タスク1.3: パフォーマンス評価**
**達成条件:**
- [ ] シャープレシオ・MaxDD・相対/絶対収益を計算する評価関数を作る
- [ ] 特定の期間の全てのウォレットアドレスに対して評価関数を実行して成績が良い順にソートする
あとCLAUDE.md
に以下の文言を試しにつけてみました。効果あるのか要検証。生成AI使ってコード生成すると一番ネックなのが、ぐちゃぐちゃになって自分で状況が把握できなくなることだと思っています。一方で毎回コードレビューするのもそれはそれで効率悪いし、できるだけ綺麗に書いてもらえるような工夫を探したいところです。
CLAUDE.md
## Development Guidelines
### Rust Development
When implementing Rust code, follow Test-Driven Development (TDD) principles and ensure thorough unit and integration testing. After any code modifications, always run `cargo test` and `cargo check` to verify no errors occur.
タスク1.1
早速やってもらいました。
今後は基本的に "@/to/path にかいてあるタスクnを実装してください"と言うだけになります。
**タスク1.1: AWS S3データ取得機能**
**達成条件:**
- [ ] S3からHyperCoreデータダウンロード(サンプルデータレベルの量で問題ない)
- [ ] LZ4圧縮ファイルの正常な解凍
- [ ] 解凍後のデータのプリント出力
実装完了
大体30分くらいで全部できたかなという印象です。AWS関連の取得にほとんど時間を取られていました。しらみ潰しに色々なコマンドを連打している感じがしたのでいくつかアドバイスをしつつなんとか切り抜けました。何も言わなかったらうまく動かなかったかもしれないですね。認証系統は難しそうです。
取得して解凍までできていそうです。
market_data
{"time":"2024-12-01T00:00:07.868461464","ver_num":1,"raw":{"channel":"l2Book","data":{"coin":"BTC","time":1733011207357,"levels":[[{"px":"96483.0","sz":"0.9518","n":3},{"px":"96480.0","sz":"0.19507","n":1},{"px":"96479.0","sz":"0.16257","n":1},{"px":"96478.0","sz":"0.00885","n":1},{"px":"96476.0","sz":"0.77","n":1},{"px":"96475.0","sz":"1.01193","n":2},{"px":"96473.0","sz":"2.1","n":3},{"px":"96471.0","sz":"0.00622","n":1},{"px":"96470.0","sz":"0.16002","n":3},{"px":"96469.0","sz":"0.00622","n":1},{"px":"96468.0","sz":"0.24077","n":2},{"px":"96467.0","sz":"0.03738","n":2},{"px":"96466.0","sz":"0.00622","n":1},{"px":"96465.0","sz":"0.7837","n":2},{"px":"96464.0","sz":"0.16002","n":2},{"px":"96463.0","sz":"0.00622","n":1},{"px":"96462.0","sz":"0.00622","n":1},{"px":"96461.0","sz":"0.23457","n":1},{"px":"96457.0","sz":"0.86","n":1},{"px":"96456.0","sz":"1.04213","n":2}],[{"px":"96484.0","sz":"1.56112","n":4},{"px":"96485.0","sz":"1.22893","n":2},{"px":"96489.0","sz":"0.03116","n":1},{"px":"96490.0","sz":"2.88808","n":1},{"px":"96491.0","sz":"0.02071","n":1},{"px":"96492.0","sz":"0.78348","n":2},{"px":"96493.0","sz":"0.00622","n":1},{"px":"96494.0","sz":"0.00622","n":1},{"px":"96495.0","sz":"0.00622","n":1},{"px":"96496.0","sz":"0.2407","n":2},{"px":"96497.0","sz":"0.00622","n":1},{"px":"96498.0","sz":"0.00622","n":1},{"px":"96499.0","sz":"0.00622","n":1},{"px":"96500.0","sz":"0.0299","n":2},{"px":"96501.0","sz":"0.39237","n":3},{"px":"96502.0","sz":"1.22718","n":2},{"px":"96503.0","sz":"0.16509","n":1},{"px":"96506.0","sz":"3.36264","n":3},{"px":"96508.0","sz":"0.21537","n":1},{"px":"96509.0","sz":"1.10637","n":3}]]}}}
{"time":"2024-12-01T00:00:08.401592599","ver_num":1,"raw":{"channel":"l2Book","data":{"coin":"BTC","time":1733011207890,"levels":[[{"px":"96483.0","sz":"0.9518","n":3},{"px":"96480.0","sz":"0.19507","n":1},{"px":"96479.0","sz":"0.16257","n":1},{"px":"96478.0","sz":"0.00885","n":1},{"px":"96476.0","sz":"0.77","n":1},{"px":"96475.0","sz":"1.01193","n":2},{"px":"96473.0","sz":"2.1","n":3},{"px":"96471.0","sz":"0.00622","n":1},{"px":"96470.0","sz":"0.16002","n":3},{"px":"96469.0","sz":"0.00622","n":1},{"px":"96468.0","sz":"0.24077","n":2},{"px":"96467.0","sz":"0.00622","n":1},{"px":"96466.0","sz":"0.00622","n":1},{"px":"96465.0","sz":"0.7837","n":2},{"px":"96464.0","sz":"0.19118","n":3},{"px":"96463.0","sz":"0.00622","n":1},{"px":"96462.0","sz":"0.00622","n":1},{"px":"96461.0","sz":"0.23457","n":1},{"px":"96457.0","sz":"0.86","n":1},{"px":"96456.0","sz":"1.04213","n":2}],[{"px":"96484.0","sz":"1.16399","n":4},{"px":"96485.0","sz":"1.22893","n":2},{"px":"96489.0","sz":"0.03116","n":1},{"px":"96490.0","sz":"2.88808","n":1},{"px":"96491.0","sz":"0.02071","n":1},{"px":"96492.0","sz":"0.78348","n":2},{"px":"96493.0","sz":"0.00622","n":1},{"px":"96494.0","sz":"0.00622","n":1},{"px":"96495.0","sz":"0.00622","n":1},{"px":"96496.0","sz":"0.2407","n":2},{"px":"96497.0","sz":"0.00622","n":1},{"px":"96498.0","sz":"0.00622","n":1},{"px":"96499.0","sz":"0.00622","n":1},{"px":"96500.0","sz":"0.0299","n":2},{"px":"96501.0","sz":"0.39237","n":3},{"px":"96502.0","sz":"1.22718","n":2},{"px":"96503.0","sz":"0.16509","n":1},{"px":"96506.0","sz":"3.36264","n":3},{"px":"96508.0","sz":"0.21537","n":1},{"px":"96509.0","sz":"1.10637","n":3}]]}}}
{"time":"2024-12-01T00:00:08.538835101","ver_num":1,"raw":{"channel":"l2Book","data":{"coin":"BTC","time":1733011208492,"levels":[[{"px":"96483.0","sz":"0.9518","n":3},{"px":"96480.0","sz":"0.19507","n":1},{"px":"96479.0","sz":"0.16257","n":1},{"px":"96478.0","sz":"0.00885","n":1},{"px":"96476.0","sz":"0.77","n":1},{"px":"96475.0","sz":"1.01193","n":2},{"px":"96473.0","sz":"2.1","n":3},{"px":"96471.0","sz":"0.00622","n":1},{"px":"96470.0","sz":"0.16002","n":3},{"px":"96469.0","sz":"0.00622","n":1},{"px":"96468.0","sz":"0.24077","n":2},{"px":"96467.0","sz":"0.00622","n":1},{"px":"96466.0","sz":"0.00622","n":1},{"px":"96465.0","sz":"0.7837","n":2},{"px":"96464.0","sz":"0.19118","n":3},{"px":"96463.0","sz":"0.00622","n":1},{"px":"96462.0","sz":"0.00622","n":1},{"px":"96461.0","sz":"0.23457","n":1},{"px":"96457.0","sz":"0.86","n":1},{"px":"96456.0","sz":"1.04213","n":2}],[{"px":"96484.0","sz":"1.61399","n":5},{"px":"96485.0","sz":"1.26009","n":3},{"px":"96490.0","sz":"2.88808","n":1},{"px":"96491.0","sz":"0.02071","n":1},{"px":"96492.0","sz":"0.78348","n":2},{"px":"96493.0","sz":"0.00622","n":1},{"px":"96494.0","sz":"0.00622","n":1},{"px":"96495.0","sz":"0.00622","n":1},{"px":"96496.0","sz":"0.2407","n":2},{"px":"96497.0","sz":"0.00622","n":1},{"px":"96498.0","sz":"0.00622","n":1},{"px":"96499.0","sz":"0.00622","n":1},{"px":"96500.0","sz":"0.0299","n":2},{"px":"96501.0","sz":"0.39237","n":3},{"px":"96502.0","sz":"1.22718","n":2},{"px":"96503.0","sz":"0.16509","n":1},{"px":"96506.0","sz":"3.36264","n":3},{"px":"96508.0","sz":"0.21537","n":1},{"px":"96509.0","sz":"1.10637","n":3},{"px":"96510.0","sz":"0.77","n":1}]]}}}
{"time":"2024-12-01T00:00:09.182823540","ver_num":1,"raw":{"channel":"l2Book","data":{"coin":"BTC","time":1733011209096,"levels":[[{"px":"96483.0","sz":"0.9518","n":3},{"px":"96480.0","sz":"0.19507","n":1},{"px":"96479.0","sz":"0.16257","n":1},{"px":"96478.0","sz":"0.00885","n":1},{"px":"96476.0","sz":"0.77","n":1},{"px":"96475.0","sz":"1.01193","n":2},{"px":"96473.0","sz":"2.1","n":3},{"px":"96471.0","sz":"0.00622","n":1},{"px":"96470.0","sz":"0.16002","n":3},{"px":"96469.0","sz":"0.00622","n":1},{"px":"96468.0","sz":"0.24077","n":2},{"px":"96467.0","sz":"0.00622","n":1},{"px":"96466.0","sz":"0.00622","n":1},{"px":"96465.0","sz":"0.7837","n":2},{"px":"96464.0","sz":"0.19118","n":3},{"px":"96463.0","sz":"0.00622","n":1},{"px":"96462.0","sz":"0.00622","n":1},{"px":"96461.0","sz":"0.23457","n":1},{"px":"96457.0","sz":"0.86","n":1},{"px":"96456.0","sz":"1.04213","n":2}],[{"px":"96484.0","sz":"1.16399","n":4},{"px":"96485.0","sz":"1.26009","n":3},{"px":"96490.0","sz":"2.88808","n":1},{"px":"96491.0","sz":"0.02071","n":1},{"px":"96492.0","sz":"0.78348","n":2},{"px":"96493.0","sz":"0.00622","n":1},{"px":"96494.0","sz":"0.22267","n":2},{"px":"96495.0","sz":"0.00622","n":1},{"px":"96496.0","sz":"0.2407","n":2},{"px":"96497.0","sz":"0.00622","n":1},{"px":"96498.0","sz":"0.00622","n":1},{"px":"96499.0","sz":"0.00622","n":1},{"px":"96500.0","sz":"0.0299","n":2},{"px":"96501.0","sz":"0.39237","n":3},{"px":"96502.0","sz":"1.22718","n":2},{"px":"96503.0","sz":"0.16509","n":1},{"px":"96506.0","sz":"3.36264","n":3},{"px":"96508.0","sz":"0.21537","n":1},{"px":"96509.0","sz":"1.10637","n":3},{"px":"96510.0","sz":"0.77","n":1}]]}}}
{"time":"2024-12-01T00:00:09.713951056","ver_num":1,"raw":{"channel":"l2Book","data":{"coin":"BTC","time":1733011209567,"levels":[[{"px":"96483.0","sz":"1.7218","n":4},{"px":"96480.0","sz":"0.19507","n":1},{"px":"96479.0","sz":"0.16257","n":1},{"px":"96478.0","sz":"0.00885","n":1},{"px":"96476.0","sz":"0.77","n":1},{"px":"96475.0","sz":"1.01193","n":2},{"px":"96473.0","sz":"2.1","n":3},{"px":"96471.0","sz":"0.00622","n":1},{"px":"96470.0","sz":"0.16002","n":3},{"px":"96469.0","sz":"0.00622","n":1},{"px":"96468.0","sz":"0.24077","n":2},{"px":"96467.0","sz":"0.00622","n":1},{"px":"96466.0","sz":"0.00622","n":1},{"px":"96465.0","sz":"0.7837","n":2},{"px":"96464.0","sz":"0.19118","n":3},{"px":"96463.0","sz":"0.00622","n":1},{"px":"96462.0","sz":"0.00622","n":1},{"px":"96461.0","sz":"0.23457","n":1},{"px":"96457.0","sz":"0.86","n":1},{"px":"96456.0","sz":"1.04213","n":2}],[{"px":"96484.0","sz":"1.16399","n":4},{"px":"96485.0","sz":"1.26009","n":3},{"px":"96490.0","sz":"2.88808","n":1},{"px":"96491.0","sz":"0.02071","n":1},{"px":"96492.0","sz":"0.78348","n":2},{"px":"96493.0","sz":"0.00622","n":1},{"px":"96494.0","sz":"0.22267","n":2},{"px":"96495.0","sz":"0.00622","n":1},{"px":"96496.0","sz":"0.2407","n":2},{"px":"96497.0","sz":"0.00622","n":1},{"px":"96498.0","sz":"0.00622","n":1},{"px":"96499.0","sz":"0.00622","n":1},{"px":"96500.0","sz":"0.0299","n":2},{"px":"96501.0","sz":"0.39237","n":3},{"px":"96502.0","sz":"1.22718","n":2},{"px":"96503.0","sz":"0.16509","n":1},{"px":"96506.0","sz":"3.36264","n":3},{"px":"96508.0","sz":"0.21537","n":1},{"px":"96509.0","sz":"0.89943","n":2},{"px":"96510.0","sz":"0.77","n":1}]]}}}
asset_ctxs
time,coin,funding,open_interest,prev_day_px,day_ntl_vlm,premium,oracle_px,mark_px,mid_px,impact_bid_px,impact_ask_px
2024-12-01T00:00:00Z,AAVE,0.00016774,67560.88,199.32,13267655.9088,0.00184188,211.74,212.04,212.135,212.13,212.1636
2024-12-01T00:00:00Z,ACE,0.00016579,57321.5,2.8828,189624.754695,0.00182634,3.121,3.1262,3.1278,3.1267,3.1292
2024-12-01T00:00:00Z,ADA,0.00005809,6061580,1.0768,14858592.74129999,0.00096469,1.0791,1.0802,1.0803,1.080141,1.080507
2024-12-01T00:00:00Z,AI,0.00018081,432270.6,0.75635,816784.994007,0.00194647,0.7809,0.78269,0.78268,0.78242,0.78298
2024-12-01T00:00:00Z,ALT,0.00013289,4913884,0.14172,550045.90081,0.00156312,0.15226,0.15252,0.152535,0.152498,0.152581
タスク1.2
ここで気づいたのですが、S3にあるデータは板情報や統計情報で取引履歴はなさそう?です。
L1(L4?)のデータが欲しいので軽く調べてみたところノードを立てるのが早そうだったので、一旦ノードを立ててデータを取得
作業ディレクトリにhl/ディレクトリをシンボリックリンクで引っ張ってきて、そこから読み取ってもらうようにしました。
それに伴って既存のタスク1.2以降を1ずつインクリメントして新しいタスク1.2を作成
**タスク1.2: Hyperliquid nodeのデータ取得**
**達成条件:**
- [ ] hlディレクトリにあるデータをRustコードで読み込み可能にしてテストケースで成功を確認する
- [ ] hlディレクトリにあるデータがどのようなデータを含んているのかを`documents/hl.md`にまとめる
実装完了
30分弱で完了。これのテストケースの評価は難しそうだったので、ドキュメントに書き起こしてもらうような形式にしてみました(以下に一部抜粋)。詳細はあまり見ていないですが、一旦良さそうな感じにまとめてくれています。
# Hyperliquid Node Data Directory Structure
## Overview
The `hl` directory contains data generated by a Hyperliquid blockchain node. This document describes the structure and contents of the data stored in this directory.
## Directory Structure
```
hl/
├── data/ # Time-series operational data
├── file_mod_time_tracker/ # Configuration files
└── hyperliquid_data/ # Node state and database files
```
## Data Formats
### 1. JSON Line-Delimited Files (NDJSON)
Most data files use newline-delimited JSON format, where each line contains a complete JSON object.
#### Block Times (`data/block_times/YYYYMMDD`)
Contains block height, timestamps, and processing duration.
**Format:**
```json
{
"height": 620617727,
"block_time": "2025-06-06T23:59:59.903545491",
"begin_block_wall_time": "2025-06-07T00:00:00.058515427",
"apply_duration": 0.008781
}
```
**Fields:**
- `height`: Block number (u64)
- `block_time`: When the block was created
- `begin_block_wall_time`: When block processing started
- `apply_duration`: Time taken to apply the block (seconds)
タスク1.3
(内容は初期バージョンから少し修正しています)
**タスク1.3: データのDB化**
**達成条件:**
- [ ] DuckDBに約定取引データを格納する(1000~10000行程度で良い)
- [ ] DuckDBを通して取引したウォレットアドレスのリストを表示できるようなコマンドの作成
- [ ] DuckDBを通して指定したウォレットアドレスの約定履歴を取得するコマンドの作成
ここで、Bash()コマンドのタイムアウトが頻発するようになりました。
● Bash(cargo build 2>&1 | tail -20)
⎿ Error: Command timed out after 2m 0.0s
ClaudeCodeが実行するコードは2分が上限になっているのでしょうか?分かりませんが、DuckDBをインポートするとかなりビルドに時間がかかるようになるため、少々厄介な感じがします。
そこで調べるとタイムアウトの時間は環境変数でいじれるみたいなので20分に変更
実装完了
ビルドに時間がかかったりする関係もありますが、1時間ちょいくらいかかって実装が完了しました。
最終的なコマンドは以下。結構良い感じになっている気がします。本当にあっているかは確かめていません。
$ ./target/debug/hl-analysis wallet-history --wallet 0xhogehoge
Wallet Summary for 0xhogehoge:
Total trades: 45
Unique coins: 31
Total PnL: -10.60 USDC
Total fees: 0.43 USDC
First trade: 2025-06-07 00:00:00
Last trade: 2025-06-07 01:00:41
Recent trades (showing up to 10):
Time Coin Price Size Side Direction PnL
------------------------------------------------------------------------------------------
2025-06-07 01:00:41 ETH 2477.4000 4.5806 A Close Long -8.2451
2025-06-07 01:00:40 SPX 1.1102 935.9000 A Open Short 0.0000
2025-06-07 01:00:38 IOTA 0.1772 91.0000 B Close Short -0.0256
2025-06-07 01:00:37 NOT 0.0021 12692.0000 A Open Short 0.0000
2025-06-07 01:00:33 SPX 1.1075 935.9000 A Open Short 0.0000
2025-06-07 01:00:33 PROMPT 0.1857 541.0000 B Close Short -1.9747
2025-06-07 01:00:28 SPX 1.1054 935.9000 A Open Short 0.0000
2025-06-07 01:00:28 USTC 0.0116 1644.0000 A Open Short 0.0000
2025-06-07 01:00:28 BRETT 0.0479 592.0000 B Short > Long -0.0402
2025-06-07 01:00:19 IOTA 0.1772 105.0000 B Close Short -0.0295
... and 35 more trades
タスク1.4
ここまできたらサクッと終わりそうです
**タスク1.4: パフォーマンス評価**
**達成条件:**
- [ ] シャープレシオ・MaxDD・相対/絶対収益を計算する評価関数を作る
- [ ] 特定の期間の全てのウォレットアドレスに対して評価関数を実行して成績が良い順にソートする
実装完了
15分くらいで終わった気がします
$ ./target/debug/hl-analysis evaluate-wallets --min-trades 10 --sort-by total_pnl
Evaluating 609 wallets...
Found 66 wallets with at least 10 trades
Top 20 wallets by total_pnl:
Wallet Trades Win% PnL Sharpe MaxDD% RelRet% PF Avg PnL
------------------------------------------------------------------------------------------------------------------------
1. 0x001 40 97.5% 25736 0.00 52.9% 257.4% 210.40 643.40
2. 0x002 439 92.7% 17383 0.00 13.9% 173.8% 31.04 39.60
3. 0x003 32 90.6% 1437 0.00 7.0% 14.4% 84.00 44.91
4. 0x004 24 100.0% 878 0.00 0.0% 8.8% 999.99 36.59
5. 0x005 33 75.8% 820 0.00 3.4% 8.2% 28.34 24.86
ウォレットアドレスは秘匿化してます。
おそらく1時間程度の情報しか見てないので精度は悪いですが、色々評価してくれていますね。頼んだ指標が全て加えた上で、親切にPFと勝率まで乗せてくれてます。ソートも好きな項目でできるようになっています。
一応軽く確認がてら一番上のウォレットを公式サイトで見ると割と優秀そうなウォレットに見えます。
(ところで他の人のウォレットを見るのにRabbyWalletのView-onlyで見ているのですが、アドレスによってはterms of useの表示が出てsignができないために先に進めなくなる現象があるのですが、突破可能なのでしょうか?知っている方教えてください。)
フェーズ1終了
とりあえずフェーズ1の実装完了しました。ClaudeCodeが動いていた時間で言うと3時間弱程度なのかなと思います。テキストの用意やら調整やらも含めて自分の実働時間としては6時間ほどかかってしまった気がします。慣れてくればもっと短縮できそうです。
ここまでの感想ですが、コード生成系は一回エラー沼にハマると抜け出せなくことが多いなという印象です。今回も最初のAWSの認証でハマっていました。こういう時にうまいこと抜け出せるような工夫が欲しいところ。
一応CLAUDE.mdに以下の文言を追加しておきました。
If errors persist even after repeated revisions, please search online to see if there are solutions for similar symptoms.
あとclaude codeは基本オートで修正するようにしているのですが、たまに珍しいコマンドを叩くときに許可を要求してくることがあってこれを見逃してしばらく待機させてしまっていることがあります。モニターが2枚あればあまり問題なさそうですが、ノートパソコンでやっているときはちょっと面倒に感じます。完全に自律的に動かしても良いのかもしれませんがしばらくはこのスタンスでいく予定です。
あとテストケースの評価もできていないですね。テストケース自体は沢山作っているのでその分開発自体はうまく進んでいるのかもしれませんが、正しい挙動なのかの保証はこちらではできていません。実際全ての実装を任せるとどの関数がどの役割があるのかもパッとみではわからないので、チェックするのに時間がかかるという問題があります。解決策は追々考えます。
ちなみに3時間弱の実装でClaudeCodeは1000行ちょい書いてくれたみたいです。
$ cloc --include-ext=rs src/
7 text files.
7 unique files.
0 files ignored.
github.com/AlDanial/cloc v 1.98 T=0.02 s (432.7 files/s, 99821.7 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Rust 7 229 39 1347
-------------------------------------------------------------------------------
SUM: 7 229 39 1347
-------------------------------------------------------------------------------
次回フェーズ2ではウォレットのより詳細な可視化と大規模データでも円滑に見えるような効率的な処理に関して実装していく予定です。
宜しければXのフォローよろしくお願いします。
次回
Discussion
面白い記事ありがとうございます!
そういうことなんですね。hypercoreで取引しているのですが規約が出るのでこの話だとbot運用しているということなのかもしれないですね。
有益な情報ありがとうございます!