Skip to content

Commit 9fbc164

Browse files
增加自动查询费率及自动订阅行情的日志消息
登录日志消息更加详细 当持仓量为0时不再计算保证金(从而减少了查询费率的次数) 修复了登录时订阅持仓合约行情实际无效的 Bug 修复了断网重连时不会发出 ConnectionEventType.TD_NET_CONNECTED 事件的 Bug 完善了 module-info.java
1 parent 6dfea3b commit 9fbc164

File tree

4 files changed

+32
-22
lines changed

4 files changed

+32
-22
lines changed

lib/build.gradle.kts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ dependencies {
3232
val depKtraderBrokerApi = "org.rationalityfrontline.ktrader:ktrader-broker-api:$pluginRequires"
3333
val depJCTP = "org.rationalityfrontline:jctp:6.6.1_P1-1.0.0"
3434
if (publishMaven) { // 发布到 Maven 仓库
35-
implementation(kotlin("stdlib"))
3635
api(depKtraderBrokerApi)
3736
compileOnly(depPf4j)
3837
implementation(depJCTP)
@@ -88,15 +87,6 @@ tasks {
8887
"Plugin-License" to pluginLicense
8988
))
9089
}
91-
test {
92-
testLogging.showStandardStreams = true
93-
useJUnitPlatform {
94-
jvmArgs = listOf(
95-
"--add-exports", "org.junit.platform.commons/org.junit.platform.commons.util=ALL-UNNAMED",
96-
"--add-exports", "org.junit.platform.commons/org.junit.platform.commons.logging=ALL-UNNAMED"
97-
)
98-
}
99-
}
10090
}
10191

10292
publishing {

lib/src/main/kotlin/module-info.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
@SuppressWarnings("requires-transitive-automatic")
22
module ktrader.broker.ctp {
3+
requires transitive kotlin.stdlib;
4+
requires transitive kotlinx.coroutines.core.jvm;
5+
requires transitive kevent;
6+
requires transitive ktrader.datatype;
37
requires transitive ktrader.broker.api;
48
requires jctp;
59
requires static org.pf4j;

lib/src/main/kotlin/org/rationalityfrontline/ktrader/broker/ctp/CtpBrokerApi.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class CtpBrokerApi(config: Map<String, Any>, kEvent: KEvent) : BrokerApi(config,
3131
if (connectTd && !tdConnected) tdApi.connect()
3232
}
3333

34-
override suspend fun close() {
34+
override fun close() {
3535
tdApi.close()
3636
mdApi.close()
3737
}

lib/src/main/kotlin/org/rationalityfrontline/ktrader/broker/ctp/CtpTdApi.kt

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
431431
}
432432

433433
/**
434-
* 查询某一特定合约的信息
434+
* 查询某一特定合约的信息。[extras.queryFee: Boolean = false]【是否查询保证金率及手续费率,如果之前没查过,可能会耗时。当 useCache 为 false 时无效】
435435
*/
436436
suspend fun queryInstrument(code: String, useCache: Boolean = true, extras: Map<String, Any>? = null): Security? {
437437
if (useCache) {
@@ -896,17 +896,21 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
896896
when (instrument.type) {
897897
SecurityType.FUTURES -> {
898898
if (instrument.commissionRate == null) {
899+
postBrokerLogEvent(LogLevel.INFO, "自动查询期货手续费率:$code")
899900
runWithRetry({ queryFuturesCommissionRate(code) }) { e -> handleException(e, "【CtpTdApi.prepareFeeCalculation】查询期货手续费率出错:$code, $e") }
900901
}
901902
if (instrument.marginRate == null) {
903+
postBrokerLogEvent(LogLevel.INFO, "自动查询期货保证金率:$code")
902904
runWithRetry({ queryFuturesMarginRate(code) }) { e -> handleException(e, "【CtpTdApi.prepareFeeCalculation】查询期货保证金率出错:$code, $e") }
903905
}
904906
}
905907
SecurityType.OPTIONS -> {
906908
if (instrument.commissionRate == null) {
909+
postBrokerLogEvent(LogLevel.INFO, "自动查询期权手续费率:$code")
907910
runWithRetry({ queryOptionsCommissionRate(code) }) { e -> handleException(e, "查询期权手续费率出错:$code, $e") }
908911
}
909912
if (instrument.marginRate == null) {
913+
postBrokerLogEvent(LogLevel.INFO, "自动查询期权保证金:$code")
910914
runWithRetry({ queryOptionsMargin(code) }) { e -> handleException(e, "查询期保证金出错:$code, $e") }
911915
}
912916
}
@@ -920,7 +924,6 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
920924
*/
921925
suspend fun prepareFeeCalculation(codes: Collection<String>? = null, extras: Map<String, Any>? = null) {
922926
if (codes == null) {
923-
// 因为 queryFuturesCommissionRate 可能会进行申报手续费的二次异步查询,所以先查手续费率
924927
runWithRetry({ queryFuturesCommissionRate() })
925928
runWithRetry({ queryFuturesMarginRate() })
926929
runWithRetry({ queryOptionsCommissionRate() })
@@ -945,6 +948,7 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
945948
// 如果缓存的 tick 为空,说明未订阅该合约,那么订阅该合约以方便后续计算
946949
if (tick == null) {
947950
try {
951+
postBrokerLogEvent(LogLevel.INFO, "自动订阅行情:$code")
948952
runBlocking { mdApi.subscribeMarketData(listOf(code)) }
949953
} catch (e: Exception) {
950954
postBrokerLogEvent(LogLevel.ERROR, "【CtpTdApi.getOrQueryTick】计算保证金时自动订阅合约行情失败:$code, $e")
@@ -975,6 +979,7 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
975979
* 计算期货保证金
976980
*/
977981
private fun calculateFuturesMargin(instrument: Security, direction: Direction, yesterdayVolume: Int, todayVolume: Int, avgOpenPrice: Double, fallback: Double): Double {
982+
if (yesterdayVolume + todayVolume == 0) return 0.0
978983
val marginRate = getOrQueryMarginRate(instrument) ?: return fallback
979984
val (tick, isLatestTick) = getOrQueryTick(instrument.code)
980985
if (tick == null) {
@@ -1015,6 +1020,7 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
10151020
* 计算期权保证金
10161021
*/
10171022
private fun calculateOptionsMargin(instrument: Security, direction: Direction, volume: Int, avgOpenPrice: Double, fallback: Double, isOpen: Boolean): Double {
1023+
if (volume == 0) return 0.0
10181024
when (direction) {
10191025
Direction.LONG -> { // 买方
10201026
return if (isOpen) avgOpenPrice * instrument.volumeMultiple else 0.0
@@ -1267,27 +1273,31 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
12671273
val result = withTimeoutOrNull(60000) {
12681274
// 请求客户端认证
12691275
try {
1276+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】客户端认证...")
12701277
reqAuthenticate()
12711278
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】客户端认证成功")
12721279
} catch (e: Exception) {
12731280
resumeRequestsWithException("connect", "请求客户端认证失败:$e")
12741281
}
12751282
// 请求用户登录
12761283
try {
1284+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】资金账户登录...")
12771285
reqUserLogin()
12781286
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】资金账户登录成功")
12791287
} catch (e: Exception) {
12801288
resumeRequestsWithException("connect", "请求用户登录失败:$e")
12811289
}
12821290
// 请求结算单确认
12831291
try {
1292+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】结算单确认...")
12841293
reqSettlementInfoConfirm()
12851294
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】结算单确认成功")
12861295
} catch (e: Exception) {
12871296
resumeRequestsWithException("connect", "请求结算单确认失败:$e")
12881297
}
12891298
// 查询全市场合约
12901299
runWithRetry({
1300+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询全市场合约...")
12911301
val allInstruments = queryAllInstruments(false, null)
12921302
allInstruments.forEach {
12931303
instruments[it.code] = it
@@ -1296,19 +1306,21 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
12961306
}
12971307
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询全市场合约成功")
12981308
}) { e ->
1299-
resumeRequestsWithException("connect", "查询全市场合约信息失败$e")
1309+
resumeRequestsWithException("connect", "查询全市场合约失败$e")
13001310
}
13011311
// 查询保证金价格类型、持仓合约的保证金率及手续费率(如果未禁止费用计算)
13021312
if (!config.disableFeeCalculation) {
13031313
// 查询保证金价格类型
13041314
runWithRetry({
1315+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询保证金价格类型...")
13051316
queryMarginPriceType()
13061317
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询保证金价格类型成功")
13071318
}) { e ->
13081319
resumeRequestsWithException("connect", "查询保证金价格类型失败:$e")
13091320
}
13101321
// 查询持仓合约的手续费率及保证金率
13111322
try {
1323+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询持仓合约手续费率及保证金率...")
13121324
prepareFeeCalculation()
13131325
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询持仓合约手续费率及保证金率成功")
13141326
} catch (e: Exception) {
@@ -1317,13 +1329,21 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
13171329
}
13181330
// 查询账户持仓
13191331
runWithRetry({
1332+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询账户持仓...")
13201333
queryPositions(useCache = false)
13211334
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询账户持仓成功")
13221335
}) { e ->
13231336
resumeRequestsWithException("connect", "查询账户持仓失败:$e")
13241337
}
1338+
// 订阅持仓合约行情(如果行情可用且未禁止自动订阅)
1339+
if (mdApi.connected && !config.disableAutoSubscribe) {
1340+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】订阅持仓合约行情...")
1341+
mdApi.subscribeMarketData(positions.keys)
1342+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】订阅持仓合约行情成功")
1343+
}
13251344
// 查询当日订单
13261345
runWithRetry({
1346+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询当日订单...")
13271347
val orders = queryOrders(onlyUnfinished = false, useCache = false)
13281348
val finishedStatus = setOf(OrderStatus.CANCELED, OrderStatus.FILLED, OrderStatus.ERROR)
13291349
orders.forEach {
@@ -1345,25 +1365,21 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
13451365
}
13461366
// 查询当日成交记录
13471367
runWithRetry({
1368+
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询当日成交记录...")
13481369
val trades = queryTrades(useCache = false)
13491370
todayTrades.addAll(trades)
13501371
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】查询当日成交记录成功")
13511372
}) { e ->
13521373
resumeRequestsWithException("connect", "查询当日成交记录失败:$e")
13531374
}
1354-
// 订阅持仓合约行情(如果行情可用且未禁止自动订阅)
1355-
if (mdApi.connected && !config.disableAutoSubscribe) {
1356-
mdApi.subscribeMarketData(positions.keys)
1357-
postBrokerLogEvent(LogLevel.INFO, "【交易接口登录】订阅持仓合约行情成功")
1358-
}
13591375
}
13601376
if (result == null) {
13611377
resumeRequestsWithException("connect", "登录操作超时")
13621378
} else {
1379+
postBrokerConnectionEvent(ConnectionEventType.TD_NET_CONNECTED)
13631380
// 如果以上的所有操作都成功,那么登录成功
13641381
if (requestMap.values.any { it.tag == "connect" }) {
13651382
connected = true
1366-
postBrokerConnectionEvent(ConnectionEventType.TD_NET_CONNECTED)
13671383
resumeRequests("connect", Unit)
13681384
}
13691385
}
@@ -2052,8 +2068,6 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
20522068
posList.forEach { calculatePosition(it, false) }
20532069
// 如果是查询总持仓,更新持仓缓存
20542070
if (request.tag == "") {
2055-
(request.continuation as Continuation<List<Position>>).resume(posList)
2056-
requestMap.remove(nRequestID)
20572071
positions.clear()
20582072
posList.forEach {
20592073
val biPosition = positions.getOrPut(it.code) { BiPosition() }
@@ -2063,6 +2077,8 @@ internal class CtpTdApi(val config: CtpConfig, val kEvent: KEvent, val sourceId:
20632077
else -> postBrokerLogEvent(LogLevel.WARNING, "【CtpTdSpi.OnRspQryInvestorPosition】查询到未知的持仓方向(${it.code}, ${it.direction}")
20642078
}
20652079
}
2080+
(request.continuation as Continuation<List<Position>>).resume(posList)
2081+
requestMap.remove(nRequestID)
20662082
} else { // 查询单合约持仓
20672083
when (request.tag) {
20682084
Direction.LONG.name -> {

0 commit comments

Comments
 (0)