ハイリキで噂のクジラをディスコードに通知してみる
話題になっている連勝中のアカウントを追跡してみる★
あまりに大量にトレードしているなら、ミラトレしてのっかろうというお話です。ディスコード通知を作ってみました。
更新:维持连胜!「胜率 100% 神秘巨鲸」再次获利离场,10.14 以来达成 12 连胜,累计获利 1,263.4 万美元🙌
— Ai 姨 (@ai_9684xtpa) October 24, 2025
今天凌晨 01:45 宣布中美元首将于周四会晤,随后 BTC 短时突破 11.1w,该巨鲸也将 $BTC & $ETH & $SOL 多单依次平仓,共获利 177.4 万美元
▶︎ BTC:获利 127.1 万美元
▶︎ ETH:获利… https://t.co/yHECRHOfuf pic.twitter.com/ChiMrdfHqN
条件(テスト版)
PC(サーバー)つけっぱなし
Discordのwebhookと監視対象アドレスは自分で設定する
トレードがあったら通知するが、5分でまとめて通知する(調節可能)
batファイルをWクリックすると起動(pyファイルと同じフォルダに格納する)
現物保有はHYPEのみ記載
送金については通知しない
わけわからん場合はHyperscanを開いて確認
※通知がエラーで止まることがある
.batファイル ※コードは参考用です
start_watch.bat
@echo off
chcp 65001 >nul
echo Hyperliquid監視botを起動します...
echo.
REM ↓ここにあなたのDiscord Webhook URLを貼り付けてください
set DISCORD_WEBHOOK=https://discord.com/api/webhooks/〇〇
REM 必要なライブラリがあるか確認
pip show websockets >nul 2>&1
if errorlevel 1 (
echo 必要なライブラリをインストール中...
pip install websockets requests python-dateutil
)
echo.
echo 監視を開始します...
echo このウィンドウを閉じると監視が停止します。
echo.
python hl_hyperliquid_multi_watch.py
REM エラーが出た場合、ウィンドウを閉じない
if errorlevel 1 (
echo.
echo エラーが発生しました。上記のエラー内容を確認してください。
pause
).pyファイル ※コードは参考用です
hl_hyperliquid_multi_watch.py
# -*- coding: utf-8 -*-
import os
import asyncio
import json
from datetime import datetime, timezone, timedelta
import requests
import websockets
from collections import defaultdict
# =========================
# 設定
# =========================
HL_WS_URL = "wss://api.hyperliquid.xyz/ws"
HL_API_URL = "https://api.hyperliquid.xyz/info"
# 監視対象アドレス一覧(ラベル付き)
WATCH_ADDRESSES = {
"0xc2a30212a8DdAc9e123944d6e29FADdCe994E5f2": "インサイダーA",
"0xb317d2bc2d3d2df5fa441b5bae0ab9d8b07283ae": "インサイダーB",
"0x8def9f50456c6c4e37fa5d3d57f108ed23992dae": "HYPEクジラA",
}
# ↓ここに直接あなたのWebhook URLを貼り付けてください
DISCORD_WEBHOOK = "あなたのWebhook URL"
# 表示設定
USE_JST = True
DEBUG_MODE = True
SHOW_CURRENT_POSITION = True
SHOW_24H_HISTORY = True
AGGREGATE_WINDOW = 300 # 5分(300秒)
RETRY_INITIAL_DELAY = 3
RETRY_MAX_DELAY = 60
PING_INTERVAL = 20
PING_TIMEOUT = 20
# 通貨名の変換マップ
COIN_NAME_MAP = {
"@107": "HYPE",
}
if not DISCORD_WEBHOOK or "あなたの" in DISCORD_WEBHOOK:
raise RuntimeError("DISCORD_WEBHOOK を設定してください。")
WATCH_ADDRESSES_LOWER = {addr.lower(): label for addr, label in WATCH_ADDRESSES.items()}
first_snapshot_processed = {}
pending_fills = defaultdict(list)
pending_timers = {}
# 現在のポジションキャッシュ(アドレスごと)
current_positions_cache = {}
# 現物保有キャッシュ(アドレスごと)- HYPEのみ
spot_holdings_cache = {}
def log(msg: str):
timestamp = datetime.now().strftime("%H:%M:%S")
print(f"[{timestamp}] {msg}")
def debug_log(msg: str):
if DEBUG_MODE:
timestamp = datetime.now().strftime("%H:%M:%S")
print(f"[DEBUG {timestamp}] {msg}")
def post_discord(content: str = None, embeds=None):
payload = {}
if content:
payload["content"] = content
if embeds:
payload["embeds"] = embeds
try:
resp = requests.post(DISCORD_WEBHOOK, json=payload, timeout=10)
resp.raise_for_status()
log("Discord送信成功")
return True
except Exception as e:
log(f"[ERROR] Discord送信失敗: {e}")
return False
def convert_coin_name(coin: str) -> str:
"""通貨名を変換(@107 → HYPE など)"""
return COIN_NAME_MAP.get(coin, coin)
def get_hypurrscan_url(address: str) -> str:
"""hypurrscanのアドレスURLを生成"""
return f"https://hypurrscan.io/address/{address}"
def get_user_fills_from_api(user_address: str, hours: int = 24):
"""REST APIから過去の約定を取得"""
try:
payload = {
"type": "userFills",
"user": user_address
}
resp = requests.post(HL_API_URL, json=payload, timeout=30)
resp.raise_for_status()
data = resp.json()
if not isinstance(data, list):
return []
cutoff_time = datetime.now(timezone.utc) - timedelta(hours=hours)
cutoff_ms = int(cutoff_time.timestamp() * 1000)
recent_fills = [f for f in data if f.get("time") and f.get("time") >= cutoff_ms]
log(f"API取得: {len(recent_fills)}件(過去{hours}時間)")
return recent_fills
except Exception as e:
log(f"[ERROR] API取得失敗: {e}")
return []
def get_spot_holdings(user_address: str):
"""現物保有を取得(HYPEのみ)"""
try:
payload = {
"type": "spotClearinghouseState",
"user": user_address
}
resp = requests.post(HL_API_URL, json=payload, timeout=30)
resp.raise_for_status()
data = resp.json()
hype_total = 0.0
if "balances" in data:
for balance in data["balances"]:
coin = balance.get("coin", "")
coin_display = convert_coin_name(coin)
# HYPEのみ処理
if coin_display == "HYPE":
total = safe_float(balance.get("total", 0))
# 1枚未満は0として扱う
if total >= 1.0:
hype_total = total
else:
hype_total = 0.0
break
# キャッシュに保存
spot_holdings_cache[user_address.lower()] = hype_total
return hype_total
except Exception as e:
log(f"[ERROR] 現物保有取得失敗: {e}")
return 0.0
def get_current_positions(user_address: str):
"""現在のポジションを取得"""
try:
payload = {
"type": "clearinghouseState",
"user": user_address
}
resp = requests.post(HL_API_URL, json=payload, timeout=30)
resp.raise_for_status()
data = resp.json()
positions = []
positions_dict = {} # 通貨ごとのポジション
if "assetPositions" in data:
for pos in data["assetPositions"]:
position_info = pos.get("position", {})
coin = position_info.get("coin", "不明")
coin_display = convert_coin_name(coin)
szi = position_info.get("szi")
if szi and float(szi) != 0:
size = float(szi)
entry_px = float(position_info.get("entryPx", 0))
unrealized_pnl = float(position_info.get("unrealizedPnl", 0))
leverage = float(position_info.get("leverage", {}).get("value", 0))
liquidation_px = position_info.get("liquidationPx")
pos_data = {
"coin": coin_display,
"size": size,
"direction": "LONG" if size > 0 else "SHORT",
"entry_price": entry_px,
"unrealized_pnl": unrealized_pnl,
"leverage": leverage,
"liquidation_px": liquidation_px
}
positions.append(pos_data)
positions_dict[coin_display] = size
# キャッシュに保存
current_positions_cache[user_address.lower()] = positions_dict
return positions
except Exception as e:
log(f"[ERROR] ポジション取得失敗: {e}")
return []
def get_current_position_for_coin(user_address: str, coin: str) -> float:
"""特定通貨の現在のポジションを取得(キャッシュから)"""
coin_display = convert_coin_name(coin)
user_addr_lower = user_address.lower()
if user_addr_lower in current_positions_cache:
return current_positions_cache[user_addr_lower].get(coin_display, 0.0)
return None # キャッシュがない場合
def get_spot_holding_for_coin(user_address: str, coin: str):
"""特定通貨の現物保有を取得(キャッシュから・HYPEのみ)"""
coin_display = convert_coin_name(coin)
user_addr_lower = user_address.lower()
# HYPEのみ対応
if coin_display != "HYPE":
return None
if user_addr_lower in spot_holdings_cache:
return spot_holdings_cache[user_addr_lower]
return None # キャッシュがない場合
def build_position_embed(trader_address: str, positions: list):
"""現在のポジション情報のembedを作成"""
trader_label = get_address_label(trader_address)
hypurrscan_url = get_hypurrscan_url(trader_address)
# 現物保有も取得(HYPEのみ)
hype_spot = get_spot_holdings(trader_address)
if not positions and hype_spot == 0:
embed = {
"title": f"📊 現在のポジション | {trader_label}",
"description": "ポジション・現物保有なし",
"url": hypurrscan_url,
"color": 0x95a5a6,
"timestamp": datetime.now(timezone.utc).isoformat()
}
return embed
fields = []
total_unrealized_pnl = 0.0
# レバレッジポジション
for pos in positions:
direction_emoji = "🟢" if pos["direction"] == "LONG" else "🔴"
size_abs = abs(pos["size"])
field_value = f"**{direction_emoji} {pos['direction']}(レバレッジ)**\n"
field_value += f"数量: **{size_abs:,.4f}**\n"
field_value += f"エントリー: ${pos['entry_price']:,.4f}\n"
if pos.get("leverage"):
field_value += f"レバレッジ: {pos['leverage']:.1f}x\n"
pnl = pos["unrealized_pnl"]
pnl_emoji = "📈" if pnl >= 0 else "📉"
field_value += f"{pnl_emoji} 含み損益: **${pnl:,.2f}**\n"
if pos.get("liquidation_px"):
field_value += f"清算価格: ${float(pos['liquidation_px']):,.4f}"
fields.append({
"name": f"💰 {pos['coin']}",
"value": field_value,
"inline": True
})
total_unrealized_pnl += pnl
# HYPE現物保有(1枚以上の場合のみ表示)
if hype_spot > 0:
if hype_spot >= 1.0:
display_amount = int(hype_spot)
else:
display_amount = 0
field_value = f"**💎 現物保有**\n"
field_value += f"合計: **{display_amount:,}枚**"
fields.append({
"name": f"💎 HYPE",
"value": field_value,
"inline": True
})
total_pnl_emoji = "📈" if total_unrealized_pnl >= 0 else "📉"
description = ""
if total_unrealized_pnl != 0:
description = f"{total_pnl_emoji} **レバレッジ含み損益: ${total_unrealized_pnl:,.2f}**"
# アドレスリンク
fields.append({
"name": "🔍 アドレス",
"value": f"[Hypurrscanで確認]({hypurrscan_url})",
"inline": False
})
position_count = len(positions)
spot_count = 1 if hype_spot > 0 else 0
footer_text = f"Hyperliquid"
if position_count > 0:
footer_text += f" | {position_count}ポジション"
if spot_count > 0:
footer_text += f" | HYPE現物保有"
embed = {
"title": f"📊 現在のポジション | {trader_label}",
"url": hypurrscan_url,
"description": description if description else None,
"color": 0x3498db,
"fields": fields,
"footer": {
"text": footer_text
},
"timestamp": datetime.now(timezone.utc).isoformat()
}
return embed
def safe_float(value, default=0.0):
try:
if value is None:
return default
if isinstance(value, (int, float)):
return float(value)
if isinstance(value, str):
return float(value)
return default
except:
return default
def fmt_ts(ts_ms):
try:
if isinstance(ts_ms, (int, float)) and ts_ms > 0:
dt = datetime.fromtimestamp(float(ts_ms) / 1000, tz=timezone.utc)
if USE_JST:
dt = dt.astimezone(timezone(timedelta(hours=9)))
return dt.strftime("%Y-%m-%d %H:%M:%S JST")
else:
return dt.strftime("%Y-%m-%d %H:%M:%S UTC")
except Exception:
pass
return ""
def get_address_label(address: str) -> str:
addr_lower = address.lower()
label = WATCH_ADDRESSES_LOWER.get(addr_lower, "Unknown")
addr_short = f"{address[:6]}...{address[-4:]}"
return f"{label} ({addr_short})"
def aggregate_fills(fills_list):
if not fills_list:
return None
groups = defaultdict(lambda: {"buy": [], "sell": []})
for fill in fills_list:
coin = fill.get("coin", "不明")
side = fill.get("side", "").lower()
if side in ["a", "b"]:
side_key = "sell" if side == "a" else "buy"
groups[coin][side_key].append(fill)
return groups
def build_aggregated_embed(trader_address: str, coin: str, side: str, fills: list, is_past_data: bool = False):
"""集約された約定データからembedを作成(HYPE現物のみ対応版)"""
# 通貨名を変換
coin_display = convert_coin_name(coin)
total_sz = 0.0
total_value = 0.0
count = len(fills)
first_time = None
last_time = None
start_position = None
# 最初のfillのstartPositionを取得
if fills:
start_position = safe_float(fills[0].get("startPosition"))
for fill in fills:
sz = safe_float(fill.get("sz"))
px = safe_float(fill.get("px"))
time_ms = fill.get("time")
total_sz += sz
total_value += sz * px
if first_time is None or (time_ms and time_ms < first_time):
first_time = time_ms
if last_time is None or (time_ms and time_ms > last_time):
last_time = time_ms
avg_price = total_value / total_sz if total_sz > 0 else 0
# 現在のポジションを取得(レバレッジ)
current_position = get_current_position_for_coin(trader_address, coin_display)
# 現物保有を取得(HYPEのみ)
spot_holding = None
if coin_display == "HYPE":
spot_holding = get_spot_holding_for_coin(trader_address, coin_display)
# ポジション情報
position_info = None
if start_position is not None:
# 開始ポジション(startPositionはレバレッジポジションのみを表す)
if start_position > 0:
start_text = f"LONG {abs(start_position):,.2f}枚"
elif start_position < 0:
start_text = f"SHORT {abs(start_position):,.2f}枚"
else:
start_text = "ポジションなし"
# 取引内容
if side == "sell":
action_text = f"{total_sz:,.2f}枚を売却"
# 現在のポジション状態(レバレッジ)
if current_position is not None:
if abs(current_position) < 0.01:
leverage_text = "ポジションなし"
elif current_position > 0:
leverage_text = f"LONG {current_position:,.2f}枚"
else:
leverage_text = f"SHORT {abs(current_position):,.2f}枚"
else:
leverage_text = "?"
# 現物保有状態(HYPEのみ)
if coin_display == "HYPE" and spot_holding is not None:
if spot_holding >= 1.0:
spot_text = f"現物 {int(spot_holding):,}枚保有"
else:
spot_text = "現物保有 0"
else:
spot_text = None
if spot_text:
position_info = f"{start_text} → {action_text}\n→ 現在: {leverage_text} / {spot_text}"
else:
position_info = f"{start_text} → {action_text}\n→ 現在: {leverage_text}"
else: # buy
action_text = f"{total_sz:,.2f}枚を購入"
# 現在のポジション状態(レバレッジ)
if current_position is not None:
if abs(current_position) < 0.01:
leverage_text = "ポジションなし"
elif current_position > 0:
leverage_text = f"LONG {current_position:,.2f}枚"
else:
leverage_text = f"SHORT {abs(current_position):,.2f}枚"
else:
leverage_text = "?"
# 現物保有状態(HYPEのみ)
if coin_display == "HYPE" and spot_holding is not None:
if spot_holding >= 1.0:
spot_text = f"現物 {int(spot_holding):,}枚保有"
else:
spot_text = "現物保有 0"
else:
spot_text = None
if spot_text:
position_info = f"{start_text} → {action_text}\n→ 現在: {leverage_text} / {spot_text}"
else:
position_info = f"{start_text} → {action_text}\n→ 現在: {leverage_text}"
# 注意書き追加
if count >= 30:
position_info += "\n※API制限により全取引データは取得できていません"
if side == "buy":
emoji = "🟢"
side_text = "買い (BUY)"
color = 0x2ecc71
else:
emoji = "🔴"
side_text = "売り (SELL)"
color = 0xe74c3c
trader_label = get_address_label(trader_address)
hypurrscan_url = get_hypurrscan_url(trader_address)
title = f"{emoji} {coin_display} {side_text} | {trader_label}"
if is_past_data:
title = f"📜 {title}"
if count >= 30:
title += f" ×{count}件+(参考)"
elif count > 1:
title += f" ×{count}件"
fields = []
# 取引情報
if position_info:
fields.append({
"name": "📊 取引情報",
"value": position_info,
"inline": False
})
# 平均約定価格
fields.append({
"name": "💰 平均約定価格",
"value": f"**${avg_price:,.4f}**",
"inline": True
})
# 時刻
time_range = fmt_ts(first_time)
if count > 1 and last_time and first_time and last_time != first_time:
last_time_str = fmt_ts(last_time)
if time_range.split()[0] == last_time_str.split()[0]:
time_range += f" ~ {last_time_str.split()[1]}"
else:
time_range += f" ~ {last_time_str}"
fields.append({
"name": "🕐 時刻",
"value": time_range,
"inline": True
})
# Hash
if fills and fills[0].get("hash"):
hash_val = fills[0].get("hash", "")
hash_short = hash_val[:10] + "..." + hash_val[-8:] if len(hash_val) > 20 else hash_val
fields.append({
"name": "🔗 Hash (最初)",
"value": f"`{hash_short}`",
"inline": False
})
# アドレスリンク
fields.append({
"name": "🔍 アドレス",
"value": f"[Hypurrscanで確認]({hypurrscan_url})",
"inline": False
})
embed = {
"title": title,
"url": hypurrscan_url,
"color": color,
"fields": fields,
"footer": {
"text": "Hyperliquid Multi-Watch" + (" | 過去24h" if is_past_data else "")
},
"timestamp": datetime.now(timezone.utc).isoformat()
}
return embed
async def send_initial_summary(user_addr: str):
"""起動時に現在のポジションと24時間履歴を表示"""
trader_label = WATCH_ADDRESSES_LOWER[user_addr]
hypurrscan_url = get_hypurrscan_url(user_addr)
# ヘッダー送信(リンク付き)
header = f"📊 **取引サマリー** | {trader_label}\n🔍 {hypurrscan_url}"
post_discord(content=header)
await asyncio.sleep(0.5)
# 現在のポジションと現物保有を取得
if SHOW_CURRENT_POSITION:
positions = get_current_positions(user_addr)
position_embed = build_position_embed(user_addr, positions)
post_discord(embeds=[position_embed])
await asyncio.sleep(1)
# 24時間の履歴を取得(参考情報)
if SHOW_24H_HISTORY:
fills = get_user_fills_from_api(user_addr, hours=24)
if fills:
log(f"過去24時間の約定処理: {len(fills)}件 ({trader_label})")
fills.sort(key=lambda x: x.get("time", 0))
groups = aggregate_fills(fills)
embeds = []
for coin, sides in groups.items():
for side_key, side_fills in sides.items():
if side_fills:
try:
embed = build_aggregated_embed(user_addr, coin, side_key, side_fills, is_past_data=True)
embeds.append(embed)
except Exception as e:
log(f"[ERROR] Embed作成失敗: {e}")
if embeds:
note = "📜 **過去24時間の取引履歴**"
post_discord(content=note)
await asyncio.sleep(0.5)
for i in range(0, len(embeds), 10):
post_discord(embeds=embeds[i:i+10])
await asyncio.sleep(1)
async def flush_pending_fills(user_addr: str):
if user_addr not in pending_fills or not pending_fills[user_addr]:
debug_log(f"保留中の約定なし: {WATCH_ADDRESSES_LOWER[user_addr]}")
return
fills = pending_fills[user_addr]
pending_fills[user_addr] = []
log(f"リアルタイム約定集約: {len(fills)}件 ({WATCH_ADDRESSES_LOWER[user_addr]})")
# 最新のポジションと現物保有を取得
get_current_positions(user_addr)
get_spot_holdings(user_addr)
groups = aggregate_fills(fills)
embeds = []
for coin, sides in groups.items():
for side_key, side_fills in sides.items():
if side_fills:
try:
embed = build_aggregated_embed(user_addr, coin, side_key, side_fills, is_past_data=False)
embeds.append(embed)
except Exception as e:
log(f"[ERROR] Embed作成失敗: {e}")
if embeds:
log(f"Discord送信開始: {len(embeds)}件のembed")
for i in range(0, len(embeds), 10):
post_discord(embeds=embeds[i:i+10])
await asyncio.sleep(0.5)
else:
log("送信するembedなし")
async def schedule_flush(user_addr: str):
debug_log(f"schedule_flush呼び出し: {WATCH_ADDRESSES_LOWER[user_addr]}, 待機時間={AGGREGATE_WINDOW}秒")
# タイマーが既に動いている場合は新規作成しない(重要な修正点)
if user_addr in pending_timers:
debug_log(f"既存タイマー動作中のため、新規タイマーは作成しない")
return
async def delayed_flush():
debug_log(f"{AGGREGATE_WINDOW}秒待機開始")
await asyncio.sleep(AGGREGATE_WINDOW)
debug_log(f"待機完了、送信開始")
await flush_pending_fills(user_addr)
if user_addr in pending_timers:
del pending_timers[user_addr]
task = asyncio.create_task(delayed_flush())
pending_timers[user_addr] = task
debug_log(f"タイマー設定完了")
async def subscribe_user_fills(ws, address: str):
sub = {
"method": "subscribe",
"subscription": {
"type": "userFills",
"user": address
}
}
await ws.send(json.dumps(sub))
async def subscribe_all(ws):
for addr in WATCH_ADDRESSES.keys():
await subscribe_user_fills(ws, addr)
await asyncio.sleep(0.2)
async def handle_messages(ws):
message_count = 0
async for raw in ws:
message_count += 1
try:
data = json.loads(raw)
except json.JSONDecodeError:
continue
channel = data.get("channel")
if channel == "error":
error_msg = data.get("data", "不明なエラー")
log(f"[ERROR] Hyperliquid: {error_msg}")
continue
if channel == "subscriptionResponse":
continue
if channel == "user" or channel == "userFills":
msg_data = data.get("data", {})
if "fills" in msg_data:
user_addr = (msg_data.get("user") or "").lower()
is_snapshot = msg_data.get("isSnapshot", False)
if user_addr in WATCH_ADDRESSES_LOWER:
fills = msg_data.get("fills", [])
if is_snapshot:
if user_addr not in first_snapshot_processed:
first_snapshot_processed[user_addr] = True
await send_initial_summary(user_addr)
continue
for fill in fills:
pending_fills[user_addr].append(fill)
log(f"新規約定: {len(fills)}件 ({WATCH_ADDRESSES_LOWER[user_addr]})")
debug_log(f"保留中の約定数: {len(pending_fills[user_addr])}")
await schedule_flush(user_addr)
async def run_forever():
delay = RETRY_INITIAL_DELAY
first_connection = True
while True:
try:
log("WebSocket接続中...")
async with websockets.connect(
HL_WS_URL,
ping_interval=PING_INTERVAL,
ping_timeout=PING_TIMEOUT,
close_timeout=5,
max_size=2**20
) as ws:
log("✅ WebSocket接続成功")
await subscribe_all(ws)
if first_connection:
addr_list = "\n".join([f"• {label} (`{addr[:8]}...`)"
for addr, label in WATCH_ADDRESSES.items()])
post_discord(content=f"✅ **Hyperliquid監視開始**\n\n監視中のアドレス({len(WATCH_ADDRESSES)}件):\n{addr_list}\n\n• リアルタイム取引を5分集約\n• レバレッジポジション・HYPE現物保有を表示\n• 過去24時間の取引履歴を表示\n• @107はHYPEとして表示\n• Hypurrscanリンク付き")
first_connection = False
await handle_messages(ws)
except (websockets.ConnectionClosed, websockets.InvalidStatusCode) as e:
log(f"[WARN] WS切断: {e}. {delay}秒後に再接続します。")
except Exception as e:
log(f"[ERROR] エラー: {e}")
import traceback
traceback.print_exc()
await asyncio.sleep(delay)
delay = min(RETRY_MAX_DELAY, delay * 2)
def main():
log("Hyperliquid監視bot起動")
log(f"監視アドレス数: {len(WATCH_ADDRESSES)}")
log(f"約定集約時間: 5分")
log(f"現在ポジション表示: {SHOW_CURRENT_POSITION}")
log(f"24時間履歴表示: {SHOW_24H_HISTORY}")
asyncio.run(run_forever())
if __name__ == "__main__":
main()
大口に逆らうな、と格言があります。
指標や突発のファンダ、別の大口の存在も気になるところですが、無理のない範囲でミラトレする分には有効な戦略だと思います。
🐋のロング損切にショート戦略で合わせていくことも可能。
※参考用コードを使うときは、AIに一回読み込ませたりして安全確認を行ってください。
感想
思い通りの通知にならず、苦労しましたが、動作したのでうれしいです。
20回やり直しましたが、完成版ではなく、他にも追加していきたいです。


コメント