refactor(cryptotail): 取消 FIXED 模式预签订单,改为触发时再签名
- 移除 PeriodContext.preSignedOrderByOutcome,周期开始仅预取参数(账户、解密、费率、CLOB 等) - ensurePeriodContext 不再预签两个 outcome 的订单 - placeOrderForTrigger 统一 FIXED/RATIO 流程,均于触发时计算 size 并签名提交 - 每次触发仅对当前 outcome 签名一次,避免预签两张仅用一张的浪费 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+31
-81
@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service
|
|||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
/** 尾盘策略固定下单价格(最高价 0.99),不再在触发时拉取最优价 */
|
/** 尾盘策略固定下单价格(最高价 0.99),不再在触发时拉取最优价 */
|
||||||
private const val TRIGGER_FIXED_PRICE = "0.99"
|
private const val TRIGGER_FIXED_PRICE = "0.99"
|
||||||
@@ -34,8 +35,8 @@ private const val TRIGGER_FIXED_PRICE = "0.99"
|
|||||||
private const val SIZE_DECIMAL_SCALE = 2
|
private const val SIZE_DECIMAL_SCALE = 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 周期内预置上下文:账户、解密凭证、费率、签名类型、CLOB 客户端;FIXED 模式含预签订单。
|
* 周期内预置上下文:账户、解密凭证、费率、签名类型、CLOB 客户端;不含预签订单。
|
||||||
* 触发时 RATIO 仅算 size 并签名提交,FIXED 直接提交预签订单。
|
* 触发时 FIXED/RATIO 均按 outcomeIndex 计算 size 并签名提交。
|
||||||
*/
|
*/
|
||||||
private data class PeriodContext(
|
private data class PeriodContext(
|
||||||
val strategy: CryptoTailStrategy,
|
val strategy: CryptoTailStrategy,
|
||||||
@@ -48,13 +49,12 @@ private data class PeriodContext(
|
|||||||
val feeRateByTokenId: Map<String, String>,
|
val feeRateByTokenId: Map<String, String>,
|
||||||
val signatureType: Int,
|
val signatureType: Int,
|
||||||
val tokenIds: List<String>,
|
val tokenIds: List<String>,
|
||||||
val marketTitle: String?,
|
val marketTitle: String?
|
||||||
val preSignedOrderByOutcome: Map<Int, NewOrderRequest>?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 尾盘策略执行服务:按周期与时间窗口检查价格并下单,每周期最多触发一次。
|
* 尾盘策略执行服务:按周期与时间窗口检查价格并下单,每周期最多触发一次。
|
||||||
* 周期开始预置账户、解密、费率、签名类型、CLOB 客户端;FIXED 模式预签两张订单,触发时仅提交;RATIO 模式触发时再算 size 并签名提交。
|
* 周期开始预置账户、解密、费率、签名类型、CLOB 客户端;触发时按 outcomeIndex 计算 size 并签名提交。
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
class CryptoTailStrategyExecutionService(
|
class CryptoTailStrategyExecutionService(
|
||||||
@@ -88,7 +88,7 @@ class CryptoTailStrategyExecutionService(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 在周期内首次需要时构建并缓存预置上下文;失败返回 null,触发流程将走完整路径。
|
* 在周期内首次需要时构建并缓存预置上下文;失败返回 null,触发流程将走完整路径。
|
||||||
* 预置:账户、解密、费率、签名类型、CLOB 客户端;FIXED 时预签两个 outcome 的订单。
|
* 预置:账户、解密、费率、签名类型、CLOB 客户端;不预签订单,触发时再签名。
|
||||||
*/
|
*/
|
||||||
private suspend fun ensurePeriodContext(
|
private suspend fun ensurePeriodContext(
|
||||||
strategy: CryptoTailStrategy,
|
strategy: CryptoTailStrategy,
|
||||||
@@ -121,45 +121,7 @@ class CryptoTailStrategyExecutionService(
|
|||||||
}
|
}
|
||||||
val signatureType = orderSigningService.getSignatureTypeForWalletType(account.walletType)
|
val signatureType = orderSigningService.getSignatureTypeForWalletType(account.walletType)
|
||||||
|
|
||||||
val preSignedOrderByOutcome: Map<Int, NewOrderRequest>? = when (strategy.amountMode.uppercase()) {
|
if (strategy.amountMode.uppercase() != "RATIO" && strategy.amountValue < BigDecimal("1")) return null
|
||||||
"RATIO" -> null
|
|
||||||
else -> {
|
|
||||||
val amountUsdc = strategy.amountValue
|
|
||||||
if (amountUsdc < BigDecimal("1")) return null
|
|
||||||
val price = BigDecimal(TRIGGER_FIXED_PRICE)
|
|
||||||
val size = computeSize(amountUsdc, price)
|
|
||||||
val orders = mutableMapOf<Int, NewOrderRequest>()
|
|
||||||
for (i in 0..1) {
|
|
||||||
if (i >= tokenIds.size) break
|
|
||||||
val tokenId = tokenIds[i]
|
|
||||||
val feeRateBps = feeRateByTokenId[tokenId] ?: "0"
|
|
||||||
try {
|
|
||||||
val signedOrder = orderSigningService.createAndSignOrder(
|
|
||||||
privateKey = decryptedKey,
|
|
||||||
makerAddress = account.proxyAddress,
|
|
||||||
tokenId = tokenId,
|
|
||||||
side = "BUY",
|
|
||||||
price = TRIGGER_FIXED_PRICE,
|
|
||||||
size = size,
|
|
||||||
signatureType = signatureType,
|
|
||||||
nonce = "0",
|
|
||||||
feeRateBps = feeRateBps,
|
|
||||||
expiration = "0"
|
|
||||||
)
|
|
||||||
orders[i] = NewOrderRequest(
|
|
||||||
order = signedOrder,
|
|
||||||
owner = account.apiKey!!,
|
|
||||||
orderType = "FAK",
|
|
||||||
deferExec = false
|
|
||||||
)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logger.warn("尾盘策略预签订单失败: strategyId=${strategy.id}, outcomeIndex=$i", e)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
orders.ifEmpty { null }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val ctx = PeriodContext(
|
val ctx = PeriodContext(
|
||||||
strategy = strategy,
|
strategy = strategy,
|
||||||
@@ -172,8 +134,7 @@ class CryptoTailStrategyExecutionService(
|
|||||||
feeRateByTokenId = feeRateByTokenId,
|
feeRateByTokenId = feeRateByTokenId,
|
||||||
signatureType = signatureType,
|
signatureType = signatureType,
|
||||||
tokenIds = tokenIds,
|
tokenIds = tokenIds,
|
||||||
marketTitle = marketTitle,
|
marketTitle = marketTitle
|
||||||
preSignedOrderByOutcome = preSignedOrderByOutcome
|
|
||||||
)
|
)
|
||||||
periodContextCache[key] = ctx
|
periodContextCache[key] = ctx
|
||||||
return ctx
|
return ctx
|
||||||
@@ -268,40 +229,29 @@ class CryptoTailStrategyExecutionService(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
val price = BigDecimal(TRIGGER_FIXED_PRICE)
|
||||||
ctx.preSignedOrderByOutcome != null -> {
|
val size = computeSize(amountUsdc, price)
|
||||||
val orderRequest = ctx.preSignedOrderByOutcome[outcomeIndex]
|
val feeRateBps = ctx.feeRateByTokenId[tokenId] ?: "0"
|
||||||
if (orderRequest != null) {
|
val signedOrder = orderSigningService.createAndSignOrder(
|
||||||
submitOrderAndSaveRecord(ctx.clobApi, strategy, periodStartUnix, marketTitle, outcomeIndex, triggerPrice, amountUsdc, orderRequest)
|
privateKey = ctx.decryptedPrivateKey,
|
||||||
return
|
makerAddress = ctx.account.proxyAddress,
|
||||||
}
|
tokenId = tokenId,
|
||||||
}
|
side = "BUY",
|
||||||
strategy.amountMode.uppercase() == "RATIO" -> {
|
price = TRIGGER_FIXED_PRICE,
|
||||||
val price = BigDecimal(TRIGGER_FIXED_PRICE)
|
size = size,
|
||||||
val size = computeSize(amountUsdc, price)
|
signatureType = ctx.signatureType,
|
||||||
val feeRateBps = ctx.feeRateByTokenId[tokenId] ?: "0"
|
nonce = "0",
|
||||||
val signedOrder = orderSigningService.createAndSignOrder(
|
feeRateBps = feeRateBps,
|
||||||
privateKey = ctx.decryptedPrivateKey,
|
expiration = "0"
|
||||||
makerAddress = ctx.account.proxyAddress,
|
)
|
||||||
tokenId = tokenId,
|
val orderRequest = NewOrderRequest(
|
||||||
side = "BUY",
|
order = signedOrder,
|
||||||
price = TRIGGER_FIXED_PRICE,
|
owner = ctx.account.apiKey!!,
|
||||||
size = size,
|
orderType = "FAK",
|
||||||
signatureType = ctx.signatureType,
|
deferExec = false
|
||||||
nonce = "0",
|
)
|
||||||
feeRateBps = feeRateBps,
|
submitOrderAndSaveRecord(ctx.clobApi, strategy, periodStartUnix, marketTitle, outcomeIndex, triggerPrice, amountUsdc, orderRequest)
|
||||||
expiration = "0"
|
return
|
||||||
)
|
|
||||||
val orderRequest = NewOrderRequest(
|
|
||||||
order = signedOrder,
|
|
||||||
owner = ctx.account.apiKey!!,
|
|
||||||
orderType = "FAK",
|
|
||||||
deferExec = false
|
|
||||||
)
|
|
||||||
submitOrderAndSaveRecord(ctx.clobApi, strategy, periodStartUnix, marketTitle, outcomeIndex, triggerPrice, amountUsdc, orderRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
placeOrderForTriggerSlowPath(strategy, periodStartUnix, marketTitle, tokenIds, outcomeIndex, triggerPrice)
|
placeOrderForTriggerSlowPath(strategy, periodStartUnix, marketTitle, tokenIds, outcomeIndex, triggerPrice)
|
||||||
|
|||||||
Reference in New Issue
Block a user