fix(trade): LIMIT
calculated quantity smaller than quoteAmountPrecision
This commit is contained in:
90
main.py
90
main.py
@@ -54,6 +54,7 @@ class MexcSpotMarket:
|
|||||||
提供获取交易对价格等功能
|
提供获取交易对价格等功能
|
||||||
|
|
||||||
方法:
|
方法:
|
||||||
|
- get_exchange_info(symbol): 获取交易对信息
|
||||||
- get_price(symbol): 获取指定交易对的当前价格
|
- get_price(symbol): 获取指定交易对的当前价格
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -61,6 +62,33 @@ class MexcSpotMarket:
|
|||||||
"""初始化市场数据查询接口"""
|
"""初始化市场数据查询接口"""
|
||||||
self.market = mexc_spot_v3.mexc_market(config)
|
self.market = mexc_spot_v3.mexc_market(config)
|
||||||
|
|
||||||
|
def get_exchange_info(self, symbol: str) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取交易对信息
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 交易对,如 "BTCUSDT"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
交易对信息字典或None(如果失败)
|
||||||
|
"""
|
||||||
|
params = {"symbol": symbol}
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.info("查询交易对信息: %s", symbol)
|
||||||
|
exchange_info = self.market.get_exchangeInfo(params)
|
||||||
|
|
||||||
|
if not exchange_info or "symbols" not in exchange_info:
|
||||||
|
logger.error("获取交易对信息失败: %s", exchange_info)
|
||||||
|
return None
|
||||||
|
|
||||||
|
logger.info("获取交易对信息成功")
|
||||||
|
return exchange_info
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("查询交易所信息失败: %s", str(e))
|
||||||
|
return None
|
||||||
|
|
||||||
def get_price(self, symbol: str) -> Optional[float]:
|
def get_price(self, symbol: str) -> Optional[float]:
|
||||||
"""
|
"""
|
||||||
获取指定交易对的当前价格
|
获取指定交易对的当前价格
|
||||||
@@ -274,6 +302,44 @@ class MexcSpotTrade:
|
|||||||
logger.error("记录交易失败: %s", str(e))
|
logger.error("记录交易失败: %s", str(e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _tool_calculate_quantity(
|
||||||
|
self,
|
||||||
|
quantity: float,
|
||||||
|
price: float,
|
||||||
|
base_asset_precision: int,
|
||||||
|
quote_amount_precision: float,
|
||||||
|
) -> float:
|
||||||
|
"""
|
||||||
|
调整下单数量以满足最小成交额要求。
|
||||||
|
|
||||||
|
策略说明:
|
||||||
|
- 计算出的quantity如果乘以price后小于交易对的最小成交额(quoteAmountPrecision),
|
||||||
|
则将quantity增加一个最小单位(10^(-base_asset_precision)),确保下单金额满足交易所要求。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
quantity: 初步计算出的下单数量
|
||||||
|
price: 当前价格
|
||||||
|
base_asset_precision: 交易对基础资产的小数精度
|
||||||
|
quote_amount_precision: 交易对最小成交额
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
满足最小成交额要求的下单数量
|
||||||
|
"""
|
||||||
|
processed_quantity = round(quantity, base_asset_precision)
|
||||||
|
if processed_quantity * price < quote_amount_precision:
|
||||||
|
logger.info(
|
||||||
|
"计算的quantity小于最低要求:%f * %f = %f < %f,进行调整",
|
||||||
|
processed_quantity,
|
||||||
|
price,
|
||||||
|
processed_quantity * price,
|
||||||
|
quote_amount_precision,
|
||||||
|
)
|
||||||
|
processed_quantity = round(
|
||||||
|
quantity + 10 ** (-base_asset_precision), base_asset_precision
|
||||||
|
)
|
||||||
|
logger.info("调整后的quantity: %f", processed_quantity)
|
||||||
|
return processed_quantity
|
||||||
|
|
||||||
def trade(
|
def trade(
|
||||||
self, symbol: str, order_type: str, side: str, **kwargs
|
self, symbol: str, order_type: str, side: str, **kwargs
|
||||||
) -> Optional[Dict[str, Any]]:
|
) -> Optional[Dict[str, Any]]:
|
||||||
@@ -322,12 +388,26 @@ class MexcSpotTrade:
|
|||||||
and "quantity" not in processed_kwargs
|
and "quantity" not in processed_kwargs
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
|
exchange_info = self.market.get_exchange_info(symbol)
|
||||||
quote_amount = float(processed_kwargs["quoteOrderQty"])
|
quote_amount = float(processed_kwargs["quoteOrderQty"])
|
||||||
price = float(processed_kwargs["price"])
|
price = (
|
||||||
|
float(current_price)
|
||||||
|
if not current_price is None
|
||||||
|
else float(processed_kwargs["price"])
|
||||||
|
)
|
||||||
quantity = quote_amount / price
|
quantity = quote_amount / price
|
||||||
processed_kwargs["quantity"] = str(quantity)
|
base_asset_precision = int(
|
||||||
|
exchange_info["symbols"][0]["baseAssetPrecision"]
|
||||||
|
)
|
||||||
|
quote_amount_precision = float(
|
||||||
|
exchange_info["symbols"][0]["quoteAmountPrecision"]
|
||||||
|
)
|
||||||
|
processed_quantity = self._tool_calculate_quantity(
|
||||||
|
quantity, price, base_asset_precision, quote_amount_precision
|
||||||
|
)
|
||||||
|
logger.info("根据quoteOrderQty计算quantity: %f", processed_quantity)
|
||||||
|
processed_kwargs["quantity"] = str(processed_quantity)
|
||||||
processed_kwargs.pop("quoteOrderQty")
|
processed_kwargs.pop("quoteOrderQty")
|
||||||
logger.info("根据quoteOrderQty计算quantity: %f", quantity)
|
|
||||||
except (ValueError, KeyError) as e:
|
except (ValueError, KeyError) as e:
|
||||||
logger.error("计算quantity失败: %s", str(e))
|
logger.error("计算quantity失败: %s", str(e))
|
||||||
return None
|
return None
|
||||||
@@ -484,6 +564,7 @@ class TradingConfig:
|
|||||||
|
|
||||||
return today_trades
|
return today_trades
|
||||||
|
|
||||||
|
|
||||||
def git_commit(repo_path: str = ".") -> str:
|
def git_commit(repo_path: str = ".") -> str:
|
||||||
"""获取Git仓库版本"""
|
"""获取Git仓库版本"""
|
||||||
|
|
||||||
@@ -493,6 +574,7 @@ def git_commit(repo_path: str = ".") -> str:
|
|||||||
except Exception as _:
|
except Exception as _:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""主函数"""
|
"""主函数"""
|
||||||
|
|
||||||
@@ -527,7 +609,7 @@ def main():
|
|||||||
spot_trader = MexcSpotTrade(
|
spot_trader = MexcSpotTrade(
|
||||||
config.config_data.get("api", {}),
|
config.config_data.get("api", {}),
|
||||||
config.config_data.get("symbol_mapping", {}),
|
config.config_data.get("symbol_mapping", {}),
|
||||||
os.path.basename(config_file).replace('.json', '')
|
os.path.basename(config_file).replace(".json", ""),
|
||||||
)
|
)
|
||||||
today_trades = config.get_today_trades()
|
today_trades = config.get_today_trades()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user