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): 获取指定交易对的当前价格
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
@@ -61,6 +62,33 @@ class MexcSpotMarket:
 | 
			
		||||
        """初始化市场数据查询接口"""
 | 
			
		||||
        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]:
 | 
			
		||||
        """
 | 
			
		||||
        获取指定交易对的当前价格
 | 
			
		||||
@@ -274,6 +302,44 @@ class MexcSpotTrade:
 | 
			
		||||
            logger.error("记录交易失败: %s", str(e))
 | 
			
		||||
            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(
 | 
			
		||||
        self, symbol: str, order_type: str, side: str, **kwargs
 | 
			
		||||
    ) -> Optional[Dict[str, Any]]:
 | 
			
		||||
@@ -322,12 +388,26 @@ class MexcSpotTrade:
 | 
			
		||||
            and "quantity" not in processed_kwargs
 | 
			
		||||
        ):
 | 
			
		||||
            try:
 | 
			
		||||
                exchange_info = self.market.get_exchange_info(symbol)
 | 
			
		||||
                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
 | 
			
		||||
                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")
 | 
			
		||||
                logger.info("根据quoteOrderQty计算quantity: %f", quantity)
 | 
			
		||||
            except (ValueError, KeyError) as e:
 | 
			
		||||
                logger.error("计算quantity失败: %s", str(e))
 | 
			
		||||
                return None
 | 
			
		||||
@@ -484,6 +564,7 @@ class TradingConfig:
 | 
			
		||||
 | 
			
		||||
        return today_trades
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def git_commit(repo_path: str = ".") -> str:
 | 
			
		||||
    """获取Git仓库版本"""
 | 
			
		||||
 | 
			
		||||
@@ -493,6 +574,7 @@ def git_commit(repo_path: str = ".") -> str:
 | 
			
		||||
    except Exception as _:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    """主函数"""
 | 
			
		||||
 | 
			
		||||
@@ -527,7 +609,7 @@ def main():
 | 
			
		||||
            spot_trader = MexcSpotTrade(
 | 
			
		||||
                config.config_data.get("api", {}),
 | 
			
		||||
                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()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user