Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,42 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.8] - 2025-10-28

### Fixed

- **关键修复**: 修正 OCO 分组常量大小写,解决止盈止损订单 422 错误
- 修改 `normalTpSl` -> `normalTpsl` (小写 s)
- 修改 `positionTpSl` -> `positionTpsl` (小写 s)
- 与 HyperLiquid SDK `Grouping` 类型定义保持完全一致
- 修复设置止盈止损时的 "Failed to deserialize the JSON body" 错误

### Added

- 新增调试脚本 `test_scripts/debug_tpsl.py` 用于验证订单格式
- 新增验证脚本 `test_scripts/test_grouping_fix.py` 用于测试修复

### Changed

- 更新相关测试和验证脚本以匹配新的常量值
- 改进订单结构注释说明

## [0.1.6] - 2025-10-27

### Fixed

- 清理错误的 v0.2.0 标签,恢复正确的版本历史
- 维护版本一致性

## [0.1.5] - 2025-10-27

### Added

- 自动格式化代码(black 和 isort)
- 优化 release.prompt 支持自动版本号递增

### Changed

- 清理冗余文档和重组文件

## [0.1.4] - Previous Release
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "hyperliquid-mcp-python"
version = "0.1.7"
version = "0.1.8"
description = "HyperLiquid MCP Server with FastMCP - Trading tools and account management"
authors = [
{name = "jettwang", email = "jamiesun.net@gmail.com"}
Expand Down
6 changes: 4 additions & 2 deletions services/constants.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""HyperLiquid MCP 常量定义"""

# OCO 订单分组类型
OCO_GROUP_NEW_POSITION = "normalTpSl" # 新仓位的括号订单
OCO_GROUP_EXISTING_POSITION = "positionTpSl" # 现有仓位的止盈止损
# 注意: 必须与 HyperLiquid SDK 中的 Grouping 类型定义一致
# SDK 定义: Literal["na"], Literal["normalTpsl"], Literal["positionTpsl"]
OCO_GROUP_NEW_POSITION = "normalTpsl" # 新仓位的括号订单 (小写 s)
OCO_GROUP_EXISTING_POSITION = "positionTpsl" # 现有仓位的止盈止损 (小写 s)

# 订单类型常量
ORDER_TYPE_LIMIT_GTC = {"limit": {"tif": "Gtc"}}
Expand Down
4 changes: 2 additions & 2 deletions services/hyperliquid_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -810,12 +810,12 @@ async def set_position_tpsl(
# Add stop loss order if specified
if sl_px is not None:
# For SL orders, use market order for fast execution
# No limit_px needed when isMarket=True
# When isMarket=True, limit_px should be 0 or the trigger price
sl_order = {
"coin": coin,
"is_buy": not is_long,
"sz": float(position_size),
"limit_px": float(sl_px), # Use trigger price as limit_px
"limit_px": float(sl_px), # For market orders, use trigger price
"order_type": {
"trigger": {
"triggerPx": float(sl_px),
Expand Down
70 changes: 70 additions & 0 deletions test_scripts/debug_tpsl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""
调试止盈止损订单的 JSON 格式
"""

import json
import os
import sys

# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from hyperliquid.utils.signing import order_type_to_wire

# 模拟一个止盈订单
tp_order = {
"coin": "BTC",
"is_buy": False, # 平多仓
"sz": 0.001,
"limit_px": 95000.0,
"order_type": {
"trigger": {
"triggerPx": 95000.0,
"isMarket": False,
"tpsl": "tp",
}
},
"reduce_only": True,
}

# 模拟一个止损订单
sl_order = {
"coin": "BTC",
"is_buy": False, # 平多仓
"sz": 0.001,
"limit_px": 90000.0,
"order_type": {
"trigger": {
"triggerPx": 90000.0,
"isMarket": True,
"tpsl": "sl",
}
},
"reduce_only": True,
}

print("=" * 60)
print("止盈订单 (TP Order):")
print("=" * 60)
print(json.dumps(tp_order, indent=2))

print("\n" + "=" * 60)
print("止损订单 (SL Order):")
print("=" * 60)
print(json.dumps(sl_order, indent=2))

# 测试 order_type 转换
print("\n" + "=" * 60)
print("TP Order Type Wire:")
print("=" * 60)
tp_wire_type = order_type_to_wire(tp_order["order_type"])
print(json.dumps(tp_wire_type, indent=2))

print("\n" + "=" * 60)
print("SL Order Type Wire:")
print("=" * 60)
sl_wire_type = order_type_to_wire(sl_order["order_type"])
print(json.dumps(sl_wire_type, indent=2))

print("\n✅ 订单类型格式验证通过!")
24 changes: 24 additions & 0 deletions test_scripts/test_grouping_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env python3
"""测试 OCO 分组常量修复"""

from services.constants import OCO_GROUP_EXISTING_POSITION, OCO_GROUP_NEW_POSITION

print("=" * 60)
print("OCO 分组常量验证")
print("=" * 60)

print(f"\nOCO_GROUP_NEW_POSITION = {repr(OCO_GROUP_NEW_POSITION)}")
print(f"OCO_GROUP_EXISTING_POSITION = {repr(OCO_GROUP_EXISTING_POSITION)}")

# 验证与 SDK 定义一致
assert OCO_GROUP_NEW_POSITION == "normalTpsl", f"错误: {OCO_GROUP_NEW_POSITION}"
assert OCO_GROUP_EXISTING_POSITION == "positionTpsl", (
f"错误: {OCO_GROUP_EXISTING_POSITION}"
)

print("\n✅ 所有常量值正确!")
print("✅ 与 HyperLiquid SDK Grouping 类型定义一致 (小写 's')")
print("\n修复说明:")
print("- 之前: normalTpSl, positionTpSl (大写 S - 错误)")
print("- 现在: normalTpsl, positionTpsl (小写 s - 正确)")
print("\n这个修复解决了 '422 Failed to deserialize the JSON body' 错误")
7 changes: 5 additions & 2 deletions test_scripts/verify_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ def check_constants():
OCO_GROUP_NEW_POSITION,
)

assert OCO_GROUP_NEW_POSITION == "normalTpSl", "新仓位分组常量错误"
assert OCO_GROUP_EXISTING_POSITION == "positionTpSl", "现有仓位分组常量错误"
# 必须与 HyperLiquid SDK 中的 Grouping 类型定义完全一致(小写 's')
assert OCO_GROUP_NEW_POSITION == "normalTpsl", "新仓位分组常量错误(应为小写s)"
assert OCO_GROUP_EXISTING_POSITION == "positionTpsl", (
"现有仓位分组常量错误(应为小写s)"
)
assert ADDRESS_PREFIX_LEN == 6, "地址前缀长度常量错误"
print("✅ 常量检查通过")

Expand Down
9 changes: 5 additions & 4 deletions tests/unit/test_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
)


def test_oco_group_constants():
"""测试 OCO 分组常量值"""
assert OCO_GROUP_NEW_POSITION == "normalTpSl"
assert OCO_GROUP_EXISTING_POSITION == "positionTpSl"
def test_oco_grouping_constants():
"""测试 OCO 分组常量与 SDK 定义一致"""
# 必须与 HyperLiquid SDK 中的 Grouping 类型定义完全一致
assert OCO_GROUP_NEW_POSITION == "normalTpsl" # 注意小写 's'
assert OCO_GROUP_EXISTING_POSITION == "positionTpsl" # 注意小写 's'


def test_order_type_constants():
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.