Harden main contract refresh
This commit is contained in:
parent
10c434013b
commit
48079cea72
@ -32,7 +32,7 @@ public class InstrumentDictionary extends BaseEntity {
|
|||||||
/** 价格放大倍数 */
|
/** 价格放大倍数 */
|
||||||
private Integer priceScale;
|
private Integer priceScale;
|
||||||
|
|
||||||
/** 最小变动价位 */
|
/** 合约最小变动价位(不参与行情价格缩放) */
|
||||||
private BigDecimal priceTick;
|
private BigDecimal priceTick;
|
||||||
|
|
||||||
/** 是否当前主力合约:0-否,1-是 */
|
/** 是否当前主力合约:0-否,1-是 */
|
||||||
|
|||||||
@ -27,8 +27,9 @@ public interface InstrumentDictionaryMapper extends BaseMapper<InstrumentDiction
|
|||||||
FROM t_instrument_dictionary
|
FROM t_instrument_dictionary
|
||||||
WHERE LOWER(contract_code) = LOWER(#{contractCode})
|
WHERE LOWER(contract_code) = LOWER(#{contractCode})
|
||||||
AND is_deleted = 0
|
AND is_deleted = 0
|
||||||
|
AND is_main = 1
|
||||||
ORDER BY id
|
ORDER BY id
|
||||||
""")
|
""")
|
||||||
List<InstrumentDictionary> selectActiveByContractCodeIgnoreCase(
|
List<InstrumentDictionary> selectMainByContractCodeIgnoreCase(
|
||||||
@Param("contractCode") String contractCode);
|
@Param("contractCode") String contractCode);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,14 +49,6 @@ public class CnQuotationClient {
|
|||||||
return parseKChartItems(body);
|
return parseKChartItems(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CnQuotationModels.ContractDetail getContractDetail(String contractCode) {
|
|
||||||
String body = get(urlBuilder("contract/detail")
|
|
||||||
.addQueryParameter("contractCode", contractCode)
|
|
||||||
.build());
|
|
||||||
JSONObject data = parseData(body);
|
|
||||||
return data == null ? null : data.toJavaObject(CnQuotationModels.ContractDetail.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CnQuotationModels.KChartItem> getKChartByDate(String excode, String code, String period,
|
public List<CnQuotationModels.KChartItem> getKChartByDate(String excode, String code, String period,
|
||||||
long date, String direction) {
|
long date, String direction) {
|
||||||
Integer type = typeOf(period);
|
Integer type = typeOf(period);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package com.yangwale.backtestify.service.market.client;
|
package com.yangwale.backtestify.service.market.client;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -23,12 +22,6 @@ public class CnQuotationModels {
|
|||||||
Integer isPrincipal) {
|
Integer isPrincipal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ContractDetail(String excode,
|
|
||||||
String contractCode,
|
|
||||||
String productId,
|
|
||||||
BigDecimal priceTick) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public record KChartResult(List<KChartItem> chats) {
|
public record KChartResult(List<KChartItem> chats) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,12 +19,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -47,6 +46,7 @@ public class MarketDataSyncService {
|
|||||||
private final MarketDataSyncLogMapper syncLogMapper;
|
private final MarketDataSyncLogMapper syncLogMapper;
|
||||||
private final KLineTableResolver tableResolver;
|
private final KLineTableResolver tableResolver;
|
||||||
private final IndicatorCalculationService indicatorCalculationService;
|
private final IndicatorCalculationService indicatorCalculationService;
|
||||||
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
@Scheduled(cron = "${market-data.sync.cron:0 0 6 * * ?}", zone = "${market-data.sync.zone:Asia/Shanghai}")
|
@Scheduled(cron = "${market-data.sync.cron:0 0 6 * * ?}", zone = "${market-data.sync.zone:Asia/Shanghai}")
|
||||||
public void syncYesterdayMainContracts() {
|
public void syncYesterdayMainContracts() {
|
||||||
@ -78,7 +78,7 @@ public class MarketDataSyncService {
|
|||||||
|
|
||||||
public void repairContractFrom(String contractCode, long startTimestamp) {
|
public void repairContractFrom(String contractCode, long startTimestamp) {
|
||||||
List<InstrumentDictionary> matches =
|
List<InstrumentDictionary> matches =
|
||||||
instrumentDictionaryMapper.selectActiveByContractCodeIgnoreCase(contractCode);
|
instrumentDictionaryMapper.selectMainByContractCodeIgnoreCase(contractCode);
|
||||||
InstrumentDictionary instrument = requireSingleContract(matches, contractCode);
|
InstrumentDictionary instrument = requireSingleContract(matches, contractCode);
|
||||||
ZoneId zoneId = properties.getSync().zoneId();
|
ZoneId zoneId = properties.getSync().zoneId();
|
||||||
LocalDateTime now = LocalDateTime.now(zoneId);
|
LocalDateTime now = LocalDateTime.now(zoneId);
|
||||||
@ -109,25 +109,18 @@ public class MarketDataSyncService {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
try {
|
try {
|
||||||
List<CnQuotationModels.GoodsItem> goodsItems = cnQuotationClient.listMainContracts();
|
List<CnQuotationModels.GoodsItem> goodsItems = cnQuotationClient.listMainContracts();
|
||||||
List<ResolvedMainContract> resolvedContracts = new ArrayList<>();
|
List<CnQuotationModels.GoodsItem> mainContracts = goodsItems.stream()
|
||||||
for (CnQuotationModels.GoodsItem item : goodsItems) {
|
.filter(item -> item.mainContractCode() != null && !item.mainContractCode().isBlank())
|
||||||
if (item.mainContractCode() == null || item.mainContractCode().isBlank()) {
|
.toList();
|
||||||
continue;
|
transactionTemplate.executeWithoutResult(status -> {
|
||||||
}
|
|
||||||
CnQuotationModels.ContractDetail detail =
|
|
||||||
cnQuotationClient.getContractDetail(item.mainContractCode());
|
|
||||||
if (detail == null || detail.priceTick() == null || detail.priceTick().signum() <= 0) {
|
|
||||||
throw new IllegalStateException("行情接口未返回有效最小变动价位: " + item.mainContractCode());
|
|
||||||
}
|
|
||||||
resolvedContracts.add(new ResolvedMainContract(item, detail.priceTick()));
|
|
||||||
}
|
|
||||||
instrumentDictionaryMapper.update(null, new LambdaUpdateWrapper<InstrumentDictionary>()
|
instrumentDictionaryMapper.update(null, new LambdaUpdateWrapper<InstrumentDictionary>()
|
||||||
.set(InstrumentDictionary::getIsMain, 0)
|
.set(InstrumentDictionary::getIsMain, 0)
|
||||||
.eq(InstrumentDictionary::getIsDeleted, 0));
|
.eq(InstrumentDictionary::getIsDeleted, 0));
|
||||||
for (ResolvedMainContract resolved : resolvedContracts) {
|
for (CnQuotationModels.GoodsItem item : mainContracts) {
|
||||||
upsertInstrument(resolved.item(), resolved.priceTick());
|
upsertInstrument(item);
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
count = mainContracts.size();
|
||||||
saveLog("CONTRACT", null, null, LocalDate.now(), "SUCCESS", count, null, start);
|
saveLog("CONTRACT", null, null, LocalDate.now(), "SUCCESS", count, null, start);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
saveLog("CONTRACT", null, null, LocalDate.now(), "FAILED", count, e.getMessage(), start);
|
saveLog("CONTRACT", null, null, LocalDate.now(), "FAILED", count, e.getMessage(), start);
|
||||||
@ -179,7 +172,7 @@ public class MarketDataSyncService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void upsertInstrument(CnQuotationModels.GoodsItem item, BigDecimal priceTick) {
|
private void upsertInstrument(CnQuotationModels.GoodsItem item) {
|
||||||
String contractCode = item.mainContractCode();
|
String contractCode = item.mainContractCode();
|
||||||
List<InstrumentDictionary> matches =
|
List<InstrumentDictionary> matches =
|
||||||
instrumentDictionaryMapper.selectByExchangeAndContractCodeIgnoreCase(
|
instrumentDictionaryMapper.selectByExchangeAndContractCodeIgnoreCase(
|
||||||
@ -193,14 +186,12 @@ public class MarketDataSyncService {
|
|||||||
instrument.setSymbol(firstNonBlank(item.productId(), item.goodsCode(), productPrefix(contractCode)));
|
instrument.setSymbol(firstNonBlank(item.productId(), item.goodsCode(), productPrefix(contractCode)));
|
||||||
instrument.setContractCode(contractCode);
|
instrument.setContractCode(contractCode);
|
||||||
instrument.setPriceScale(DEFAULT_PRICE_SCALE);
|
instrument.setPriceScale(DEFAULT_PRICE_SCALE);
|
||||||
instrument.setPriceTick(priceTick);
|
|
||||||
instrument.setIsMain(1);
|
instrument.setIsMain(1);
|
||||||
instrumentDictionaryMapper.insert(instrument);
|
instrumentDictionaryMapper.insert(instrument);
|
||||||
} else {
|
} else {
|
||||||
existing.setExchangeId(item.excode());
|
existing.setExchangeId(item.excode());
|
||||||
existing.setSymbol(firstNonBlank(item.productId(), item.goodsCode(), productPrefix(contractCode)));
|
existing.setSymbol(firstNonBlank(item.productId(), item.goodsCode(), productPrefix(contractCode)));
|
||||||
existing.setContractCode(contractCode);
|
existing.setContractCode(contractCode);
|
||||||
existing.setPriceTick(priceTick);
|
|
||||||
existing.setIsMain(1);
|
existing.setIsMain(1);
|
||||||
existing.setIsDeleted(0);
|
existing.setIsDeleted(0);
|
||||||
instrumentDictionaryMapper.updateById(existing);
|
instrumentDictionaryMapper.updateById(existing);
|
||||||
@ -267,7 +258,4 @@ public class MarketDataSyncService {
|
|||||||
}
|
}
|
||||||
return contractCode.replaceAll("\\d+$", "");
|
return contractCode.replaceAll("\\d+$", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private record ResolvedMainContract(CnQuotationModels.GoodsItem item, BigDecimal priceTick) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,7 @@ USE backtestify;
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for bt_strategy_config
|
-- Table structure for bt_strategy_config
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `bt_strategy_config`;
|
CREATE TABLE IF NOT EXISTS `bt_strategy_config` (
|
||||||
CREATE TABLE `bt_strategy_config` (
|
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||||
`contract_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '合约代码',
|
`contract_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '合约代码',
|
||||||
@ -40,8 +39,7 @@ CREATE TABLE `bt_strategy_config` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for bt_strategy_result
|
-- Table structure for bt_strategy_result
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `bt_strategy_result`;
|
CREATE TABLE IF NOT EXISTS `bt_strategy_result` (
|
||||||
CREATE TABLE `bt_strategy_result` (
|
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
`strategy_id` bigint NOT NULL COMMENT '关联策略ID',
|
`strategy_id` bigint NOT NULL COMMENT '关联策略ID',
|
||||||
`initial_capital` decimal(18, 2) NOT NULL COMMENT '初始资金',
|
`initial_capital` decimal(18, 2) NOT NULL COMMENT '初始资金',
|
||||||
@ -66,8 +64,7 @@ CREATE TABLE `bt_strategy_result` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for bt_trade_detail
|
-- Table structure for bt_trade_detail
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `bt_trade_detail`;
|
CREATE TABLE IF NOT EXISTS `bt_trade_detail` (
|
||||||
CREATE TABLE `bt_trade_detail` (
|
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
`strategy_id` bigint NOT NULL COMMENT '关联策略ID',
|
`strategy_id` bigint NOT NULL COMMENT '关联策略ID',
|
||||||
`action` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作: BUY_OPEN/SELL_CLOSE/SELL_OPEN/BUY_CLOSE',
|
`action` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作: BUY_OPEN/SELL_CLOSE/SELL_OPEN/BUY_CLOSE',
|
||||||
@ -86,8 +83,7 @@ CREATE TABLE `bt_trade_detail` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for bt_user_signal
|
-- Table structure for bt_user_signal
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `bt_user_signal`;
|
CREATE TABLE IF NOT EXISTS `bt_user_signal` (
|
||||||
CREATE TABLE `bt_user_signal` (
|
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||||
`strategy_id` bigint NOT NULL COMMENT '策略ID',
|
`strategy_id` bigint NOT NULL COMMENT '策略ID',
|
||||||
@ -105,8 +101,7 @@ CREATE TABLE `bt_user_signal` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_15m
|
-- Table structure for t_indicator_15m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_15m`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_15m` (
|
||||||
CREATE TABLE `t_indicator_15m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -134,8 +129,7 @@ CREATE TABLE `t_indicator_15m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_1d
|
-- Table structure for t_indicator_1d
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_1d`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_1d` (
|
||||||
CREATE TABLE `t_indicator_1d` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -163,8 +157,7 @@ CREATE TABLE `t_indicator_1d` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_1h
|
-- Table structure for t_indicator_1h
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_1h`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_1h` (
|
||||||
CREATE TABLE `t_indicator_1h` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -192,8 +185,7 @@ CREATE TABLE `t_indicator_1h` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_1m
|
-- Table structure for t_indicator_1m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_1m`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_1m` (
|
||||||
CREATE TABLE `t_indicator_1m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL,
|
`ma5` decimal(18, 6) NULL DEFAULT NULL,
|
||||||
@ -221,8 +213,7 @@ CREATE TABLE `t_indicator_1m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_1mo
|
-- Table structure for t_indicator_1mo
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_1mo`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_1mo` (
|
||||||
CREATE TABLE `t_indicator_1mo` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -250,8 +241,7 @@ CREATE TABLE `t_indicator_1mo` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_1w
|
-- Table structure for t_indicator_1w
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_1w`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_1w` (
|
||||||
CREATE TABLE `t_indicator_1w` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -279,8 +269,7 @@ CREATE TABLE `t_indicator_1w` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_30m
|
-- Table structure for t_indicator_30m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_30m`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_30m` (
|
||||||
CREATE TABLE `t_indicator_30m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -308,8 +297,7 @@ CREATE TABLE `t_indicator_30m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_3m
|
-- Table structure for t_indicator_3m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_3m`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_3m` (
|
||||||
CREATE TABLE `t_indicator_3m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -337,8 +325,7 @@ CREATE TABLE `t_indicator_3m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_4h
|
-- Table structure for t_indicator_4h
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_4h`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_4h` (
|
||||||
CREATE TABLE `t_indicator_4h` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -366,8 +353,7 @@ CREATE TABLE `t_indicator_4h` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_indicator_5m
|
-- Table structure for t_indicator_5m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_indicator_5m`;
|
CREATE TABLE IF NOT EXISTS `t_indicator_5m` (
|
||||||
CREATE TABLE `t_indicator_5m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,对应K线起始点)',
|
||||||
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
`ma5` decimal(18, 6) NULL DEFAULT NULL COMMENT 'MA5',
|
||||||
@ -395,20 +381,20 @@ CREATE TABLE `t_indicator_5m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_instrument_dictionary
|
-- Table structure for t_instrument_dictionary
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_instrument_dictionary`;
|
CREATE TABLE IF NOT EXISTS `t_instrument_dictionary` (
|
||||||
CREATE TABLE `t_instrument_dictionary` (
|
|
||||||
`id` smallint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '合约自增ID',
|
`id` smallint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '合约自增ID',
|
||||||
`exchange_id` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
`exchange_id` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
||||||
`symbol` varchar(10) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
`symbol` varchar(10) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
||||||
`contract_code` varchar(20) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
`contract_code` varchar(20) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
||||||
|
`contract_code_normalized` varchar(20) CHARACTER SET ascii COLLATE ascii_general_ci GENERATED ALWAYS AS (lower(`contract_code`)) STORED,
|
||||||
`price_scale` int UNSIGNED NOT NULL DEFAULT 1000 COMMENT '价格放大倍数(暂统一使用1000)',
|
`price_scale` int UNSIGNED NOT NULL DEFAULT 1000 COMMENT '价格放大倍数(暂统一使用1000)',
|
||||||
`price_tick` decimal(18, 6) NOT NULL COMMENT '最小变动价位;历史源tb_quotations_futures_contract.price_tick,增量源contract/detail.priceTick',
|
`price_tick` decimal(18, 6) NOT NULL DEFAULT 1 COMMENT '合约最小变动价位,不参与行情价格缩放',
|
||||||
`is_main` tinyint NOT NULL DEFAULT 0 COMMENT '是否当前主力合约: 0-否, 1-是',
|
`is_main` tinyint NOT NULL DEFAULT 0 COMMENT '是否当前主力合约: 0-否, 1-是',
|
||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
`is_deleted` tinyint NOT NULL DEFAULT 0 COMMENT '逻辑删除: 0-未删除, 1-已删除',
|
`is_deleted` tinyint NOT NULL DEFAULT 0 COMMENT '逻辑删除: 0-未删除, 1-已删除',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_exchange_contract`(`exchange_id` ASC, `contract_code` ASC) USING BTREE,
|
UNIQUE INDEX `uk_exchange_contract`(`exchange_id` ASC, `contract_code_normalized` ASC) USING BTREE,
|
||||||
INDEX `idx_symbol_main`(`symbol` ASC, `is_main` ASC) USING BTREE,
|
INDEX `idx_symbol_main`(`symbol` ASC, `is_main` ASC) USING BTREE,
|
||||||
INDEX `idx_contract_code`(`contract_code` ASC) USING BTREE
|
INDEX `idx_contract_code`(`contract_code` ASC) USING BTREE
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 2048 CHARACTER SET = ascii COLLATE = ascii_general_ci COMMENT = '期货合约字典表' ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB AUTO_INCREMENT = 2048 CHARACTER SET = ascii COLLATE = ascii_general_ci COMMENT = '期货合约字典表' ROW_FORMAT = Dynamic;
|
||||||
@ -416,8 +402,7 @@ CREATE TABLE `t_instrument_dictionary` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_15m
|
-- Table structure for t_kline_15m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_15m`;
|
CREATE TABLE IF NOT EXISTS `t_kline_15m` (
|
||||||
CREATE TABLE `t_kline_15m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -434,8 +419,7 @@ CREATE TABLE `t_kline_15m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_1d
|
-- Table structure for t_kline_1d
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_1d`;
|
CREATE TABLE IF NOT EXISTS `t_kline_1d` (
|
||||||
CREATE TABLE `t_kline_1d` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -453,8 +437,7 @@ CREATE TABLE `t_kline_1d` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_1h
|
-- Table structure for t_kline_1h
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_1h`;
|
CREATE TABLE IF NOT EXISTS `t_kline_1h` (
|
||||||
CREATE TABLE `t_kline_1h` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -471,8 +454,7 @@ CREATE TABLE `t_kline_1h` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_1m
|
-- Table structure for t_kline_1m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_1m`;
|
CREATE TABLE IF NOT EXISTS `t_kline_1m` (
|
||||||
CREATE TABLE `t_kline_1m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -489,8 +471,7 @@ CREATE TABLE `t_kline_1m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_1mo
|
-- Table structure for t_kline_1mo
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_1mo`;
|
CREATE TABLE IF NOT EXISTS `t_kline_1mo` (
|
||||||
CREATE TABLE `t_kline_1mo` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -507,8 +488,7 @@ CREATE TABLE `t_kline_1mo` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_1w
|
-- Table structure for t_kline_1w
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_1w`;
|
CREATE TABLE IF NOT EXISTS `t_kline_1w` (
|
||||||
CREATE TABLE `t_kline_1w` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -525,8 +505,7 @@ CREATE TABLE `t_kline_1w` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_30m
|
-- Table structure for t_kline_30m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_30m`;
|
CREATE TABLE IF NOT EXISTS `t_kline_30m` (
|
||||||
CREATE TABLE `t_kline_30m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -543,8 +522,7 @@ CREATE TABLE `t_kline_30m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_3m
|
-- Table structure for t_kline_3m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_3m`;
|
CREATE TABLE IF NOT EXISTS `t_kline_3m` (
|
||||||
CREATE TABLE `t_kline_3m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -561,8 +539,7 @@ CREATE TABLE `t_kline_3m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_4h
|
-- Table structure for t_kline_4h
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_4h`;
|
CREATE TABLE IF NOT EXISTS `t_kline_4h` (
|
||||||
CREATE TABLE `t_kline_4h` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -579,8 +556,7 @@ CREATE TABLE `t_kline_4h` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_kline_5m
|
-- Table structure for t_kline_5m
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_kline_5m`;
|
CREATE TABLE IF NOT EXISTS `t_kline_5m` (
|
||||||
CREATE TABLE `t_kline_5m` (
|
|
||||||
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
`instrument_id` smallint UNSIGNED NOT NULL COMMENT '合约字典ID',
|
||||||
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
`k_time` int UNSIGNED NOT NULL COMMENT 'Unix时间戳 (秒级,每根K线起始点)',
|
||||||
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
`open` int NOT NULL COMMENT '开盘价 (实际价格 * price_scale)',
|
||||||
@ -597,8 +573,7 @@ CREATE TABLE `t_kline_5m` (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for t_market_data_sync_log
|
-- Table structure for t_market_data_sync_log
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `t_market_data_sync_log`;
|
CREATE TABLE IF NOT EXISTS `t_market_data_sync_log` (
|
||||||
CREATE TABLE `t_market_data_sync_log` (
|
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
`sync_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '同步类型: CONTRACT/KLINE',
|
`sync_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '同步类型: CONTRACT/KLINE',
|
||||||
`f_period` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'K线周期',
|
`f_period` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'K线周期',
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.yangwale.backtestify.service.market.sync;
|
package com.yangwale.backtestify.service.market.sync;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
import com.yangwale.backtestify.config.MarketDataProperties;
|
import com.yangwale.backtestify.config.MarketDataProperties;
|
||||||
import com.yangwale.backtestify.entity.InstrumentDictionary;
|
import com.yangwale.backtestify.entity.InstrumentDictionary;
|
||||||
@ -14,16 +14,21 @@ import com.yangwale.backtestify.service.market.client.CnQuotationClient;
|
|||||||
import com.yangwale.backtestify.service.market.client.CnQuotationModels;
|
import com.yangwale.backtestify.service.market.client.CnQuotationModels;
|
||||||
import com.yangwale.backtestify.service.market.indicator.IndicatorCalculationService;
|
import com.yangwale.backtestify.service.market.indicator.IndicatorCalculationService;
|
||||||
import com.yangwale.backtestify.service.market.repository.KLineTableResolver;
|
import com.yangwale.backtestify.service.market.repository.KLineTableResolver;
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.support.SimpleTransactionStatus;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyList;
|
import static org.mockito.ArgumentMatchers.anyList;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
@ -78,7 +83,8 @@ class MarketDataSyncServiceTest {
|
|||||||
instrument.setExchangeId("CZCE");
|
instrument.setExchangeId("CZCE");
|
||||||
instrument.setContractCode("AP610");
|
instrument.setContractCode("AP610");
|
||||||
instrument.setPriceScale(1000);
|
instrument.setPriceScale(1000);
|
||||||
when(instrumentMapper.selectActiveByContractCodeIgnoreCase("ap610"))
|
instrument.setIsMain(1);
|
||||||
|
when(instrumentMapper.selectMainByContractCodeIgnoreCase("ap610"))
|
||||||
.thenReturn(List.of(instrument));
|
.thenReturn(List.of(instrument));
|
||||||
CapturingRepairQuotationClient quotationClient = new CapturingRepairQuotationClient(properties);
|
CapturingRepairQuotationClient quotationClient = new CapturingRepairQuotationClient(properties);
|
||||||
|
|
||||||
@ -91,6 +97,21 @@ class MarketDataSyncServiceTest {
|
|||||||
verify(indicatorService).rebuild("1d", 7);
|
verify(indicatorService).rebuild("1d", 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void repairRejectsContractThatIsNotCurrentMain() {
|
||||||
|
MarketDataProperties properties = new MarketDataProperties();
|
||||||
|
InstrumentDictionaryMapper instrumentMapper = mock(InstrumentDictionaryMapper.class);
|
||||||
|
when(instrumentMapper.selectMainByContractCodeIgnoreCase("AP610"))
|
||||||
|
.thenReturn(List.of());
|
||||||
|
|
||||||
|
MarketDataSyncService service = service(properties,
|
||||||
|
new EmptyQuotationClient(properties), instrumentMapper, mock(KLineMapper.class),
|
||||||
|
mock(MarketDataSyncLogMapper.class), mock(IndicatorCalculationService.class));
|
||||||
|
|
||||||
|
assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> service.repairContractFrom("AP610", 100L));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void refreshPreservesExistingPriceScale() {
|
void refreshPreservesExistingPriceScale() {
|
||||||
MarketDataProperties properties = new MarketDataProperties();
|
MarketDataProperties properties = new MarketDataProperties();
|
||||||
@ -109,12 +130,11 @@ class MarketDataSyncServiceTest {
|
|||||||
new EmptyQuotationClient(properties), instrumentMapper, kLineMapper,
|
new EmptyQuotationClient(properties), instrumentMapper, kLineMapper,
|
||||||
syncLogMapper, indicatorService);
|
syncLogMapper, indicatorService);
|
||||||
|
|
||||||
ReflectionTestUtils.invokeMethod(service, "upsertInstrument", goodsItem(), new BigDecimal("0.5"));
|
ReflectionTestUtils.invokeMethod(service, "upsertInstrument", goodsItem());
|
||||||
|
|
||||||
ArgumentCaptor<InstrumentDictionary> updated = ArgumentCaptor.forClass(InstrumentDictionary.class);
|
ArgumentCaptor<InstrumentDictionary> updated = ArgumentCaptor.forClass(InstrumentDictionary.class);
|
||||||
verify(instrumentMapper).updateById(updated.capture());
|
verify(instrumentMapper).updateById(updated.capture());
|
||||||
assertEquals(500, updated.getValue().getPriceScale());
|
assertEquals(500, updated.getValue().getPriceScale());
|
||||||
assertEquals(new BigDecimal("0.5"), updated.getValue().getPriceTick());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -129,12 +149,11 @@ class MarketDataSyncServiceTest {
|
|||||||
new EmptyQuotationClient(properties), instrumentMapper, kLineMapper,
|
new EmptyQuotationClient(properties), instrumentMapper, kLineMapper,
|
||||||
syncLogMapper, indicatorService);
|
syncLogMapper, indicatorService);
|
||||||
|
|
||||||
ReflectionTestUtils.invokeMethod(service, "upsertInstrument", goodsItem(), new BigDecimal("0.5"));
|
ReflectionTestUtils.invokeMethod(service, "upsertInstrument", goodsItem());
|
||||||
|
|
||||||
ArgumentCaptor<InstrumentDictionary> inserted = ArgumentCaptor.forClass(InstrumentDictionary.class);
|
ArgumentCaptor<InstrumentDictionary> inserted = ArgumentCaptor.forClass(InstrumentDictionary.class);
|
||||||
verify(instrumentMapper).insert(inserted.capture());
|
verify(instrumentMapper).insert(inserted.capture());
|
||||||
assertEquals(1000, inserted.getValue().getPriceScale());
|
assertEquals(1000, inserted.getValue().getPriceScale());
|
||||||
assertEquals(new BigDecimal("0.5"), inserted.getValue().getPriceTick());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -164,7 +183,8 @@ class MarketDataSyncServiceTest {
|
|||||||
kLineMapper,
|
kLineMapper,
|
||||||
syncLogMapper,
|
syncLogMapper,
|
||||||
new KLineTableResolver(),
|
new KLineTableResolver(),
|
||||||
indicatorService) {
|
indicatorService,
|
||||||
|
transactionTemplate()) {
|
||||||
@Override
|
@Override
|
||||||
public void refreshMainContracts() {
|
public void refreshMainContracts() {
|
||||||
// Contract refresh is outside this test's synchronization seam.
|
// Contract refresh is outside this test's synchronization seam.
|
||||||
@ -203,7 +223,7 @@ class MarketDataSyncServiceTest {
|
|||||||
when(kLineMapper.selectLatestTimestamp("t_kline_1d", 7)).thenReturn(100L);
|
when(kLineMapper.selectLatestTimestamp("t_kline_1d", 7)).thenReturn(100L);
|
||||||
MarketDataSyncService service = new MarketDataSyncService(
|
MarketDataSyncService service = new MarketDataSyncService(
|
||||||
properties, quotationClient, instrumentMapper, kLineMapper, syncLogMapper,
|
properties, quotationClient, instrumentMapper, kLineMapper, syncLogMapper,
|
||||||
new KLineTableResolver(), indicatorService) {
|
new KLineTableResolver(), indicatorService, transactionTemplate()) {
|
||||||
@Override
|
@Override
|
||||||
public void refreshMainContracts() {
|
public void refreshMainContracts() {
|
||||||
// Contract refresh is outside this test's synchronization seam.
|
// Contract refresh is outside this test's synchronization seam.
|
||||||
@ -234,7 +254,8 @@ class MarketDataSyncServiceTest {
|
|||||||
|
|
||||||
MarketDataSyncService service = new MarketDataSyncService(
|
MarketDataSyncService service = new MarketDataSyncService(
|
||||||
properties, new RepairQuotationClient(properties), instrumentMapper,
|
properties, new RepairQuotationClient(properties), instrumentMapper,
|
||||||
kLineMapper, syncLogMapper, new KLineTableResolver(), indicatorService) {
|
kLineMapper, syncLogMapper, new KLineTableResolver(), indicatorService,
|
||||||
|
transactionTemplate()) {
|
||||||
@Override
|
@Override
|
||||||
public void refreshMainContracts() {
|
public void refreshMainContracts() {
|
||||||
// Contract refresh is outside this test's synchronization seam.
|
// Contract refresh is outside this test's synchronization seam.
|
||||||
@ -264,7 +285,8 @@ class MarketDataSyncServiceTest {
|
|||||||
instrument.setExchangeId("SHFE");
|
instrument.setExchangeId("SHFE");
|
||||||
instrument.setContractCode("rb2610");
|
instrument.setContractCode("rb2610");
|
||||||
instrument.setPriceScale(1000);
|
instrument.setPriceScale(1000);
|
||||||
when(instrumentMapper.selectActiveByContractCodeIgnoreCase("rb2610"))
|
instrument.setIsMain(1);
|
||||||
|
when(instrumentMapper.selectMainByContractCodeIgnoreCase("rb2610"))
|
||||||
.thenReturn(List.of(instrument));
|
.thenReturn(List.of(instrument));
|
||||||
|
|
||||||
MarketDataSyncService service = service(properties, new RepairQuotationClient(properties),
|
MarketDataSyncService service = service(properties, new RepairQuotationClient(properties),
|
||||||
@ -285,7 +307,24 @@ class MarketDataSyncServiceTest {
|
|||||||
IndicatorCalculationService indicatorService) {
|
IndicatorCalculationService indicatorService) {
|
||||||
return new MarketDataSyncService(
|
return new MarketDataSyncService(
|
||||||
properties, quotationClient, instrumentMapper, kLineMapper, syncLogMapper,
|
properties, quotationClient, instrumentMapper, kLineMapper, syncLogMapper,
|
||||||
new KLineTableResolver(), indicatorService);
|
new KLineTableResolver(), indicatorService, transactionTemplate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private TransactionTemplate transactionTemplate() {
|
||||||
|
return new TransactionTemplate(new PlatformTransactionManager() {
|
||||||
|
@Override
|
||||||
|
public TransactionStatus getTransaction(TransactionDefinition definition) {
|
||||||
|
return new SimpleTransactionStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commit(TransactionStatus status) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollback(TransactionStatus status) {
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private CnQuotationModels.GoodsItem goodsItem() {
|
private CnQuotationModels.GoodsItem goodsItem() {
|
||||||
@ -368,12 +407,6 @@ class MarketDataSyncServiceTest {
|
|||||||
return List.of(new CnQuotationModels.GoodsItem(
|
return List.of(new CnQuotationModels.GoodsItem(
|
||||||
"CZCE", "AP", "AP", "苹果", "AP610", 1));
|
"CZCE", "AP", "AP", "苹果", "AP610", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public CnQuotationModels.ContractDetail getContractDetail(String contractCode) {
|
|
||||||
return new CnQuotationModels.ContractDetail(
|
|
||||||
"CZCE", contractCode, "AP", new BigDecimal("1"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class CapturingRepairQuotationClient extends EmptyQuotationClient {
|
private static final class CapturingRepairQuotationClient extends EmptyQuotationClient {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ CREATE TABLE IF NOT EXISTS t_instrument_dictionary (
|
|||||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||||
UNIQUE (contract_code)
|
UNIQUE (exchange_id, contract_code)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS t_kline_1m (
|
CREATE TABLE IF NOT EXISTS t_kline_1m (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user