chore(assets): 参赛提交规范红线修复(ASCII 化 + 相对路径)
按《参赛成果物提交规范·赛道一》§6 红线: - samples/ 目录改名 sample/(git mv,保留历史) - 10 个中日文样本文件 + docs 参赛手册 PDF 重命名为 ASCII (requirements_*/template_*/rules_*/contestant-handbook.pdf) - tests/test_zh_template.py 硬编码绝对路径 D:\00_project\Genesis 改为相对路径 - 全局更新 21 个活动文件引用;历史日志/审查文档不改(追加说明记录) 全量 pytest 431 passed / 99.15%
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.stock</groupId>
|
||||
<artifactId>stock-trade-system</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.stock</groupId>
|
||||
<artifactId>trade-strategy</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>trade-strategy</name>
|
||||
<description>Trading strategy definition and execution module</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot Starter Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis Plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL Connector -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Hutool -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- trade-common -->
|
||||
<dependency>
|
||||
<groupId>com.stock</groupId>
|
||||
<artifactId>trade-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- trade-indicator (to use indicators in strategies) -->
|
||||
<dependency>
|
||||
<groupId>com.stock</groupId>
|
||||
<artifactId>trade-indicator</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- trade-market-data (to get market data for strategy execution) -->
|
||||
<dependency>
|
||||
<groupId>com.stock</groupId>
|
||||
<artifactId>trade-market-data</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud Nacos Discovery -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud OpenFeign -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringDoc OpenAPI -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional: Drools or other rule engines for complex strategy logic -->
|
||||
<!-- <dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-core</artifactId>
|
||||
<version>LATEST_VERSION</version>
|
||||
</dependency> -->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.stock.strategy.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 策略控制器
|
||||
*
|
||||
* @author TraeAI
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/strategy")
|
||||
public class StrategyController {
|
||||
// TODO: 实现策略相关接口
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.stock.strategy.dal.dataobject;
|
||||
|
||||
import com.stock.common.dal.dataobject.BaseDO; // 引入公共BaseDO
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 策略DO
|
||||
*
|
||||
* @author TraeAI
|
||||
*/
|
||||
@TableName("trade_strategy") // TODO: 确认表名是否正确
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class StrategyDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 策略名称
|
||||
*/
|
||||
private String strategyName;
|
||||
|
||||
/**
|
||||
* 策略类型
|
||||
*/
|
||||
private String strategyType;
|
||||
|
||||
/**
|
||||
* 策略描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 策略内容 (例如: JSON格式的参数,或者脚本语言)
|
||||
*/
|
||||
private String content;
|
||||
|
||||
// TODO: 根据实际需求添加更多字段
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.stock.strategy.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.stock.strategy.dal.dataobject.StrategyDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 策略 Mapper
|
||||
*
|
||||
* @author TraeAI
|
||||
*/
|
||||
@Mapper
|
||||
public interface StrategyMapper extends BaseMapper<StrategyDO> {
|
||||
// TODO: 定义策略相关的数据库操作方法
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.stock.strategy.service;
|
||||
|
||||
/**
|
||||
* 策略服务接口
|
||||
*
|
||||
* @author TraeAI
|
||||
*/
|
||||
public interface StrategyService {
|
||||
// TODO: 定义策略服务相关方法
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.stock.strategy.service.impl;
|
||||
|
||||
import com.stock.strategy.service.StrategyService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 策略服务实现类
|
||||
*
|
||||
* @author TraeAI
|
||||
*/
|
||||
@Service
|
||||
public class StrategyServiceImpl implements StrategyService {
|
||||
// TODO: 实现策略服务相关方法
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package com.stock.trade.strategy.controller;
|
||||
|
||||
import com.stock.trade.framework.common.pojo.CommonResult;
|
||||
import com.stock.trade.framework.common.pojo.PageResult;
|
||||
import com.stock.trade.strategy.controller.vo.StrategyExecutionCreateReqVO;
|
||||
import com.stock.trade.strategy.controller.vo.StrategyExecutionPageReqVO;
|
||||
import com.stock.trade.strategy.controller.vo.StrategyExecutionRespVO;
|
||||
import com.stock.trade.strategy.controller.vo.StrategyExecutionUpdateReqVO;
|
||||
import com.stock.trade.strategy.convert.StrategyExecutionConvert;
|
||||
import com.stock.trade.strategy.dal.dataobject.StrategyExecutionDO;
|
||||
import com.stock.trade.strategy.service.StrategyExecutionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static com.stock.trade.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 策略执行")
|
||||
@RestController
|
||||
@RequestMapping("/trade/strategy-execution")
|
||||
@Validated
|
||||
public class StrategyExecutionController {
|
||||
|
||||
@Resource
|
||||
private StrategyExecutionService strategyExecutionService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建策略执行")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:create')")
|
||||
public CommonResult<Long> createStrategyExecution(@Valid @RequestBody StrategyExecutionCreateReqVO createReqVO) {
|
||||
return success(strategyExecutionService.createStrategyExecution(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新策略执行")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:update')")
|
||||
public CommonResult<Boolean> updateStrategyExecution(@Valid @RequestBody StrategyExecutionUpdateReqVO updateReqVO) {
|
||||
strategyExecutionService.updateStrategyExecution(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/start/{id}")
|
||||
@Operation(summary = "启动策略执行")
|
||||
@Parameter(name = "id", description = "策略执行编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:start')")
|
||||
public CommonResult<Boolean> startStrategyExecution(@PathVariable("id") Long id) {
|
||||
strategyExecutionService.startStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/pause/{id}")
|
||||
@Operation(summary = "暂停策略执行")
|
||||
@Parameter(name = "id", description = "策略执行编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:pause')")
|
||||
public CommonResult<Boolean> pauseStrategyExecution(@PathVariable("id") Long id) {
|
||||
strategyExecutionService.pauseStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/stop/{id}")
|
||||
@Operation(summary = "停止策略执行")
|
||||
@Parameter(name = "id", description = "策略执行编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:stop')")
|
||||
public CommonResult<Boolean> stopStrategyExecution(@PathVariable("id") Long id) {
|
||||
strategyExecutionService.stopStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除策略执行")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:delete')")
|
||||
public CommonResult<Boolean> deleteStrategyExecution(@RequestParam("id") Long id) {
|
||||
strategyExecutionService.deleteStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得策略执行")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:query')")
|
||||
public CommonResult<StrategyExecutionRespVO> getStrategyExecution(@RequestParam("id") Long id) {
|
||||
StrategyExecutionDO execution = strategyExecutionService.getStrategyExecution(id);
|
||||
return success(StrategyExecutionConvert.INSTANCE.convert(execution));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得策略执行分页")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:query')")
|
||||
public CommonResult<PageResult<StrategyExecutionRespVO>> getStrategyExecutionPage(@Valid StrategyExecutionPageReqVO pageVO) {
|
||||
PageResult<StrategyExecutionDO> pageResult = strategyExecutionService.getStrategyExecutionPage(pageVO);
|
||||
return success(StrategyExecutionConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-definition")
|
||||
@Operation(summary = "根据策略定义ID获得策略执行列表")
|
||||
@Parameter(name = "strategyDefinitionId", description = "策略定义编号", required = true, example = "2048")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:query')")
|
||||
public CommonResult<List<StrategyExecutionRespVO>> getStrategyExecutionListByDefinitionId(@RequestParam("strategyDefinitionId") Long strategyDefinitionId) {
|
||||
List<StrategyExecutionDO> list = strategyExecutionService.getStrategyExecutionListByDefinitionId(strategyDefinitionId);
|
||||
return success(StrategyExecutionConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.stock.trade.strategy.enums;
|
||||
|
||||
import com.stock.trade.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* Trade Strategy 模块错误码常量
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 策略定义 模块 1-001-000-000 ==========
|
||||
ErrorCode STRATEGY_DEFINITION_NOT_EXISTS = new ErrorCode(1001000000, "策略定义不存在");
|
||||
ErrorCode STRATEGY_DEFINITION_NAME_EXISTS = new ErrorCode(1001000001, "策略定义名称已存在");
|
||||
ErrorCode STRATEGY_DEFINITION_CANNOT_DELETE_WHEN_ACTIVE = new ErrorCode(1001000002, "策略定义处于活动状态,无法删除");
|
||||
|
||||
|
||||
// ========== 策略回测 模块 1-001-001-000 ==========
|
||||
ErrorCode STRATEGY_BACKTEST_NOT_EXISTS = new ErrorCode(1001001000, "策略回测记录不存在");
|
||||
ErrorCode STRATEGY_BACKTEST_CANNOT_START = new ErrorCode(1001001001, "当前状态无法启动策略回测");
|
||||
ErrorCode STRATEGY_BACKTEST_CANNOT_UPDATE_NON_PENDING = new ErrorCode(1001001002, "只有待处理状态的回测才能更新");
|
||||
ErrorCode STRATEGY_BACKTEST_CANNOT_DELETE_WHEN_RUNNING = new ErrorCode(1001001003, "运行中的策略回测无法删除");
|
||||
|
||||
|
||||
// ========== 策略执行 模块 1-001-002-000 ==========
|
||||
ErrorCode STRATEGY_EXECUTION_NOT_EXISTS = new ErrorCode(1001002000, "策略执行记录不存在");
|
||||
ErrorCode STRATEGY_EXECUTION_STATUS_CANNOT_START = new ErrorCode(1001002001, "当前状态无法启动策略执行");
|
||||
ErrorCode STRATEGY_EXECUTION_STATUS_CANNOT_PAUSE = new ErrorCode(1001002002, "当前状态无法暂停策略执行");
|
||||
ErrorCode STRATEGY_EXECUTION_STATUS_CANNOT_STOP = new ErrorCode(1001002003, "当前状态无法停止策略执行");
|
||||
ErrorCode STRATEGY_EXECUTION_STATUS_CANNOT_COMPLETE = new ErrorCode(1001002004, "当前状态无法完成策略执行");
|
||||
ErrorCode STRATEGY_EXECUTION_CANNOT_DELETE_WHEN_RUNNING = new ErrorCode(1001002005, "运行中的策略执行无法删除");
|
||||
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
package com.stock.trade.strategy.service;
|
||||
|
||||
import com.stock.trade.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.stock.trade.framework.common.pojo.PageResult;
|
||||
import com.stock.trade.strategy.controller.vo.StrategyExecutionCreateReqVO;
|
||||
import com.stock.trade.strategy.controller.vo.StrategyExecutionPageReqVO;
|
||||
import com.stock.trade.strategy.controller.vo.StrategyExecutionUpdateReqVO;
|
||||
import com.stock.trade.strategy.convert.StrategyExecutionConvert;
|
||||
import com.stock.trade.strategy.dal.dataobject.StrategyExecutionDO;
|
||||
import com.stock.trade.strategy.dal.mysql.StrategyExecutionMapper;
|
||||
import com.stock.trade.strategy.enums.ErrorCodeConstants;
|
||||
import com.stock.trade.strategy.enums.StrategyExecutionStatusEnum;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.stock.trade.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 策略执行 Service 实现类
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class StrategyExecutionServiceImpl implements StrategyExecutionService {
|
||||
|
||||
@Resource
|
||||
private StrategyExecutionMapper strategyExecutionMapper;
|
||||
|
||||
/**
|
||||
* 创建策略执行记录
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
@Override
|
||||
public Long createStrategyExecution(StrategyExecutionCreateReqVO createReqVO) {
|
||||
// 插入
|
||||
StrategyExecutionDO strategyExecution = StrategyExecutionConvert.INSTANCE.convert(createReqVO);
|
||||
strategyExecution.setStatus(StrategyExecutionStatusEnum.PENDING.getStatus());
|
||||
strategyExecution.setCreateTime(LocalDateTime.now());
|
||||
strategyExecution.setUpdateTime(LocalDateTime.now());
|
||||
strategyExecutionMapper.insert(strategyExecution);
|
||||
// 返回
|
||||
return strategyExecution.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新策略执行记录
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
@Override
|
||||
public void updateStrategyExecution(StrategyExecutionUpdateReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateStrategyExecutionExists(updateReqVO.getId());
|
||||
// 更新
|
||||
StrategyExecutionDO updateDO = StrategyExecutionConvert.INSTANCE.convert(updateReqVO);
|
||||
updateDO.setUpdateTime(LocalDateTime.now());
|
||||
strategyExecutionMapper.updateById(updateDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动策略执行
|
||||
*
|
||||
* @param id 策略执行ID
|
||||
*/
|
||||
@Override
|
||||
public void startStrategyExecution(Long id) {
|
||||
StrategyExecutionDO execution = validateStrategyExecutionExists(id);
|
||||
if (!Objects.equals(execution.getStatus(), StrategyExecutionStatusEnum.PENDING.getStatus()) &&
|
||||
!Objects.equals(execution.getStatus(), StrategyExecutionStatusEnum.PAUSED.getStatus())) {
|
||||
throw exception(ErrorCodeConstants.STRATEGY_EXECUTION_STATUS_CANNOT_START);
|
||||
}
|
||||
StrategyExecutionDO updateDO = new StrategyExecutionDO();
|
||||
updateDO.setId(id);
|
||||
updateDO.setStatus(StrategyExecutionStatusEnum.RUNNING.getStatus());
|
||||
updateDO.setStartTime(LocalDateTime.now()); // 记录启动时间
|
||||
updateDO.setUpdateTime(LocalDateTime.now());
|
||||
strategyExecutionMapper.updateById(updateDO);
|
||||
// 此处应有实际的策略启动逻辑,例如与交易API交互,发送到执行引擎等
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停策略执行
|
||||
*
|
||||
* @param id 策略执行ID
|
||||
*/
|
||||
@Override
|
||||
public void pauseStrategyExecution(Long id) {
|
||||
StrategyExecutionDO execution = validateStrategyExecutionExists(id);
|
||||
if (!Objects.equals(execution.getStatus(), StrategyExecutionStatusEnum.RUNNING.getStatus())) {
|
||||
throw exception(ErrorCodeConstants.STRATEGY_EXECUTION_STATUS_CANNOT_PAUSE);
|
||||
}
|
||||
StrategyExecutionDO updateDO = new StrategyExecutionDO();
|
||||
updateDO.setId(id);
|
||||
updateDO.setStatus(StrategyExecutionStatusEnum.PAUSED.getStatus());
|
||||
updateDO.setUpdateTime(LocalDateTime.now());
|
||||
strategyExecutionMapper.updateById(updateDO);
|
||||
// 此处应有实际的策略暂停逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止策略执行
|
||||
*
|
||||
* @param id 策略执行ID
|
||||
*/
|
||||
@Override
|
||||
public void stopStrategyExecution(Long id) {
|
||||
StrategyExecutionDO execution = validateStrategyExecutionExists(id);
|
||||
if (Objects.equals(execution.getStatus(), StrategyExecutionStatusEnum.COMPLETED.getStatus()) ||
|
||||
Objects.equals(execution.getStatus(), StrategyExecutionStatusEnum.FAILED.getStatus()) ||
|
||||
Objects.equals(execution.getStatus(), StrategyExecutionStatusEnum.STOPPED.getStatus())) {
|
||||
throw exception(ErrorCodeConstants.STRATEGY_EXECUTION_STATUS_CANNOT_STOP);
|
||||
}
|
||||
StrategyExecutionDO updateDO = new StrategyExecutionDO();
|
||||
updateDO.setId(id);
|
||||
updateDO.setStatus(StrategyExecutionStatusEnum.STOPPED.getStatus());
|
||||
updateDO.setEndTime(LocalDateTime.now()); // 记录停止时间
|
||||
updateDO.setUpdateTime(LocalDateTime.now());
|
||||
strategyExecutionMapper.updateById(updateDO);
|
||||
// 此处应有实际的策略停止逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除策略执行记录
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
@Override
|
||||
public void deleteStrategyExecution(Long id) {
|
||||
// 校验存在
|
||||
StrategyExecutionDO execution = validateStrategyExecutionExists(id);
|
||||
// 校验是否运行中
|
||||
if (Objects.equals(execution.getStatus(), StrategyExecutionStatusEnum.RUNNING.getStatus())) {
|
||||
throw exception(ErrorCodeConstants.STRATEGY_EXECUTION_CANNOT_DELETE_WHEN_RUNNING);
|
||||
}
|
||||
// 删除
|
||||
strategyExecutionMapper.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验策略执行记录是否存在
|
||||
*
|
||||
* @param id 策略执行ID
|
||||
* @return 策略执行实体
|
||||
*/
|
||||
private StrategyExecutionDO validateStrategyExecutionExists(Long id) {
|
||||
StrategyExecutionDO execution = strategyExecutionMapper.selectById(id);
|
||||
if (execution == null) {
|
||||
throw exception(ErrorCodeConstants.STRATEGY_EXECUTION_NOT_EXISTS);
|
||||
}
|
||||
return execution;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取策略执行记录
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 策略执行记录
|
||||
*/
|
||||
@Override
|
||||
public StrategyExecutionDO getStrategyExecution(Long id) {
|
||||
return strategyExecutionMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取策略执行记录列表
|
||||
*
|
||||
* @param ids 编号列表
|
||||
* @return 策略执行记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyExecutionDO> getStrategyExecutionList(List<Long> ids) {
|
||||
return strategyExecutionMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取策略执行记录分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 策略执行记录分页
|
||||
*/
|
||||
@Override
|
||||
public PageResult<StrategyExecutionDO> getStrategyExecutionPage(StrategyExecutionPageReqVO pageReqVO) {
|
||||
return strategyExecutionMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略定义ID获取策略执行记录列表
|
||||
*
|
||||
* @param strategyDefinitionId 策略定义ID
|
||||
* @return 策略执行记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyExecutionDO> getStrategyExecutionListByDefinitionId(Long strategyDefinitionId) {
|
||||
return strategyExecutionMapper.selectListByStrategyDefinitionId(strategyDefinitionId);
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.trade.strategy;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
/**
|
||||
* 策略服务启动类
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients // 如果需要调用其他服务,则开启 Feign
|
||||
public class StrategyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StrategyApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 策略服务启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ \\ \\ \\ / / \\n" +
|
||||
" | ( ' ) | \ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\ \ | || |(_,_)' \n" +
|
||||
" | | \ `' /| `-' / \n" +
|
||||
" | | \ / \ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.trade.strategy;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
/**
|
||||
* 交易策略服务启动类
|
||||
*/
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication
|
||||
public class TradeStrategyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TradeStrategyApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的切面类 (Aspect Class)。
|
||||
* <p>
|
||||
* 切面类用于实现横切关注点,例如日志记录、事务管理、权限校验、性能监控等。
|
||||
* 通常使用 Spring AOP 或 AspectJ 来定义和织入切面。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.aspect;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的配置类。
|
||||
*/
|
||||
package com.trade.strategy.config;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的常量类 (Constant Class)。
|
||||
* <p>
|
||||
* 常量类用于定义在应用程序中广泛使用的静态常量值,例如配置键名、默认参数、固定字符串等。
|
||||
* 将常量集中管理有助于提高代码的可维护性和一致性。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.constant;
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package com.trade.strategy.controller;
|
||||
|
||||
import com.trade.strategy.entity.StrategyBacktest;
|
||||
import com.trade.strategy.service.StrategyBacktestService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 策略回测API接口
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/strategies/backtests")
|
||||
@Tag(name = "StrategyBacktestController", description = "策略回测管理API")
|
||||
public class StrategyBacktestController {
|
||||
|
||||
@Autowired
|
||||
private StrategyBacktestService strategyBacktestService;
|
||||
|
||||
/**
|
||||
* 创建新的策略回测任务
|
||||
*
|
||||
* @param strategyBacktest 回测任务基本信息
|
||||
* @return 创建的回测任务
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "创建新的策略回测任务")
|
||||
public ResponseEntity<StrategyBacktest> createBacktest(@RequestBody StrategyBacktest strategyBacktest) {
|
||||
try {
|
||||
StrategyBacktest createdBacktest = strategyBacktestService.createBacktest(strategyBacktest);
|
||||
return new ResponseEntity<>(createdBacktest, HttpStatus.CREATED);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(null); // Consider returning error message
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动一个指定ID的回测任务
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @return 启动后的回测任务状态
|
||||
*/
|
||||
@PostMapping("/{backtestId}/start")
|
||||
@Operation(summary = "启动一个指定ID的回测任务")
|
||||
public ResponseEntity<StrategyBacktest> startBacktest(@PathVariable Long backtestId) {
|
||||
try {
|
||||
StrategyBacktest startedBacktest = strategyBacktestService.startBacktest(backtestId);
|
||||
return ResponseEntity.ok(startedBacktest);
|
||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||
return ResponseEntity.badRequest().body(null); // Consider returning error message
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (模拟) 更新回测任务的状态和结果 - 实际应由回测引擎回调
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @param payload 包含 status 和 resultDetails 的请求体
|
||||
* @return 更新后的回测任务
|
||||
*/
|
||||
@PutMapping("/{backtestId}/update-result") // This endpoint is more for internal/engine callback simulation
|
||||
@Operation(summary = "(模拟)更新回测任务的状态和结果", description = "实际场景中此接口可能由回测引擎内部调用或通过消息队列触发")
|
||||
public ResponseEntity<StrategyBacktest> updateBacktestResult(
|
||||
@PathVariable Long backtestId,
|
||||
@RequestBody Map<String, String> payload) {
|
||||
try {
|
||||
String status = payload.get("status");
|
||||
String resultDetails = payload.get("resultDetails");
|
||||
if (status == null || resultDetails == null) {
|
||||
return ResponseEntity.badRequest().body(null); // Missing parameters
|
||||
}
|
||||
StrategyBacktest updatedBacktest = strategyBacktestService.updateBacktestStatusAndResult(backtestId, status, resultDetails);
|
||||
return ResponseEntity.ok(updatedBacktest);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据ID查询策略回测记录
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @return 回测任务详情
|
||||
*/
|
||||
@GetMapping("/{backtestId}")
|
||||
@Operation(summary = "根据ID查询策略回测记录")
|
||||
public ResponseEntity<StrategyBacktest> getBacktestById(@PathVariable Long backtestId) {
|
||||
StrategyBacktest backtest = strategyBacktestService.getBacktestById(backtestId);
|
||||
if (backtest != null) {
|
||||
return ResponseEntity.ok(backtest);
|
||||
} else {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定策略定义的所有回测记录
|
||||
*
|
||||
* @param strategyDefinitionId 策略定义ID
|
||||
* @return 回测记录列表
|
||||
*/
|
||||
@GetMapping("/by-definition/{strategyDefinitionId}")
|
||||
@Operation(summary = "查询指定策略定义的所有回测记录")
|
||||
public ResponseEntity<List<StrategyBacktest>> getBacktestsByStrategyDefinitionId(@PathVariable Long strategyDefinitionId) {
|
||||
List<StrategyBacktest> backtests = strategyBacktestService.getBacktestsByStrategyDefinitionId(strategyDefinitionId);
|
||||
return ResponseEntity.ok(backtests);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有策略回测记录
|
||||
*
|
||||
* @return 所有回测记录列表
|
||||
*/
|
||||
@GetMapping
|
||||
@Operation(summary = "查询所有策略回测记录")
|
||||
public ResponseEntity<List<StrategyBacktest>> getAllBacktests() {
|
||||
List<StrategyBacktest> backtests = strategyBacktestService.getAllBacktests();
|
||||
return ResponseEntity.ok(backtests);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID删除策略回测记录
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/{backtestId}")
|
||||
@Operation(summary = "根据ID删除策略回测记录")
|
||||
public ResponseEntity<Void> deleteBacktest(@PathVariable Long backtestId) {
|
||||
try {
|
||||
strategyBacktestService.deleteBacktest(backtestId);
|
||||
return ResponseEntity.noContent().build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.notFound().build();
|
||||
} catch (IllegalStateException e) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); // Or another appropriate status for non-deletable state
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package com.trade.strategy.controller;
|
||||
|
||||
import com.trade.strategy.entity.StrategyDefinition;
|
||||
import com.trade.strategy.service.StrategyDefinitionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 交易策略定义API接口
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/strategies/definitions")
|
||||
@Tag(name = "StrategyDefinitionController", description = "交易策略定义管理API")
|
||||
public class StrategyDefinitionController {
|
||||
|
||||
@Autowired
|
||||
private StrategyDefinitionService strategyDefinitionService;
|
||||
|
||||
/**
|
||||
* 创建新的交易策略定义
|
||||
*
|
||||
* @param strategyDefinition 策略定义对象
|
||||
* @return 创建的策略定义
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "创建新的交易策略定义")
|
||||
public ResponseEntity<StrategyDefinition> createStrategy(@RequestBody StrategyDefinition strategyDefinition) {
|
||||
try {
|
||||
StrategyDefinition createdStrategy = strategyDefinitionService.createStrategy(strategyDefinition);
|
||||
return new ResponseEntity<>(createdStrategy, HttpStatus.CREATED);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(null); // 或者返回更详细的错误信息
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新已有的交易策略定义
|
||||
*
|
||||
* @param id 策略ID
|
||||
* @param strategyDefinition 策略定义对象
|
||||
* @return 更新后的策略定义
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新已有的交易策略定义")
|
||||
public ResponseEntity<StrategyDefinition> updateStrategy(@PathVariable Long id, @RequestBody StrategyDefinition strategyDefinition) {
|
||||
try {
|
||||
strategyDefinition.setId(id); // 确保ID一致
|
||||
StrategyDefinition updatedStrategy = strategyDefinitionService.updateStrategy(strategyDefinition);
|
||||
return ResponseEntity.ok(updatedStrategy);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(null); // 或者返回更详细的错误信息
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID删除交易策略定义
|
||||
*
|
||||
* @param id 策略ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "根据ID删除交易策略定义")
|
||||
public ResponseEntity<Void> deleteStrategy(@PathVariable Long id) {
|
||||
try {
|
||||
strategyDefinitionService.deleteStrategy(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询交易策略定义
|
||||
*
|
||||
* @param id 策略ID
|
||||
* @return 策略定义
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "根据ID查询交易策略定义")
|
||||
public ResponseEntity<StrategyDefinition> getStrategyById(@PathVariable Long id) {
|
||||
StrategyDefinition strategy = strategyDefinitionService.getStrategyById(id);
|
||||
if (strategy != null) {
|
||||
return ResponseEntity.ok(strategy);
|
||||
} else {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有交易策略定义
|
||||
*
|
||||
* @return 策略定义列表
|
||||
*/
|
||||
@GetMapping
|
||||
@Operation(summary = "查询所有交易策略定义")
|
||||
public ResponseEntity<List<StrategyDefinition>> getAllStrategies() {
|
||||
List<StrategyDefinition> strategies = strategyDefinitionService.getAllStrategies();
|
||||
return ResponseEntity.ok(strategies);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略名称查询交易策略定义
|
||||
*
|
||||
* @param name 策略名称
|
||||
* @return 策略定义
|
||||
*/
|
||||
@GetMapping("/by-name")
|
||||
@Operation(summary = "根据策略名称查询交易策略定义")
|
||||
public ResponseEntity<StrategyDefinition> getStrategyByName(@RequestParam String name) {
|
||||
StrategyDefinition strategy = strategyDefinitionService.getStrategyByName(name);
|
||||
if (strategy != null) {
|
||||
return ResponseEntity.ok(strategy);
|
||||
} else {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略类型查询交易策略定义
|
||||
*
|
||||
* @param type 策略类型
|
||||
* @return 策略定义列表
|
||||
*/
|
||||
@GetMapping("/by-type")
|
||||
@Operation(summary = "根据策略类型查询交易策略定义")
|
||||
public ResponseEntity<List<StrategyDefinition>> getStrategiesByType(@RequestParam String type) {
|
||||
List<StrategyDefinition> strategies = strategyDefinitionService.getStrategiesByType(type);
|
||||
return ResponseEntity.ok(strategies);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略状态查询交易策略定义
|
||||
*
|
||||
* @param status 策略状态
|
||||
* @return 策略定义列表
|
||||
*/
|
||||
@GetMapping("/by-status")
|
||||
@Operation(summary = "根据策略状态查询交易策略定义")
|
||||
public ResponseEntity<List<StrategyDefinition>> getStrategiesByStatus(@RequestParam String status) {
|
||||
List<StrategyDefinition> strategies = strategyDefinitionService.getStrategiesByStatus(status);
|
||||
return ResponseEntity.ok(strategies);
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的Controller层,负责处理HTTP请求和响应。
|
||||
*/
|
||||
package com.trade.strategy.controller;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的数据传输对象 (DTO)。
|
||||
*/
|
||||
package com.trade.strategy.dto;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略执行引擎相关的类,包括策略的加载、执行、事件处理等。
|
||||
*/
|
||||
package com.trade.strategy.engine;
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.trade.strategy.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 策略回测记录实体类
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("ts_strategy_backtest")
|
||||
public class StrategyBacktest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 回测ID (主键, 自增)
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 关联的策略定义ID
|
||||
*/
|
||||
private Long strategyDefinitionId;
|
||||
|
||||
/**
|
||||
* 回测名称 (用户自定义)
|
||||
*/
|
||||
private String backtestName;
|
||||
|
||||
/**
|
||||
* 回测开始日期
|
||||
*/
|
||||
private LocalDate startDate;
|
||||
|
||||
/**
|
||||
* 回测结束日期
|
||||
*/
|
||||
private LocalDate endDate;
|
||||
|
||||
/**
|
||||
* 初始资金
|
||||
*/
|
||||
private BigDecimal initialCapital;
|
||||
|
||||
/**
|
||||
* 手续费率 (例如: 0.0003 表示万分之三)
|
||||
*/
|
||||
private BigDecimal commissionRate;
|
||||
|
||||
/**
|
||||
* 回测状态 (例如: "PENDING", "RUNNING", "COMPLETED", "FAILED")
|
||||
* 可以考虑使用枚举类定义
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 回测结果 (JSON格式,存储回测的各项指标)
|
||||
* 例如: {"total_return": 0.15, "annualized_return": 0.30, "sharpe_ratio": 1.5, "max_drawdown": 0.10}
|
||||
*/
|
||||
private String resultDetails; // 数据库中建议使用TEXT/JSON类型
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间 (例如回测完成或失败时更新)
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.trade.strategy.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 交易策略定义实体类
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("ts_strategy_definition")
|
||||
public class StrategyDefinition implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 策略ID (主键, 自增)
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 策略名称 (必填, 唯一)
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 策略描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 策略作者
|
||||
*/
|
||||
private String author;
|
||||
|
||||
/**
|
||||
* 策略版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 策略类型 (例如: "TREND_FOLLOWING", "MEAN_REVERSION", "EVENT_DRIVEN")
|
||||
* 可以考虑使用枚举类定义
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 策略脚本内容或配置 (存储策略的具体逻辑或配置)
|
||||
* 对于复杂策略,可能存储脚本语言代码 (如Python, Groovy) 或JSON/XML配置
|
||||
*/
|
||||
private String scriptContent; // 数据库中建议使用TEXT类型
|
||||
|
||||
/**
|
||||
* 策略参数 (JSON格式,存储策略的可配置参数及其默认值)
|
||||
* 例如: {"MA_short": 5, "MA_long": 20, "stop_loss_pct": 0.05}
|
||||
*/
|
||||
private String parameters; // 数据库中建议使用TEXT/JSON类型
|
||||
|
||||
/**
|
||||
* 策略状态 (例如: "DRAFT", "ACTIVE", "INACTIVE", "ARCHIVED")
|
||||
* 可以考虑使用枚举类定义
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的数据库实体类。
|
||||
*/
|
||||
package com.trade.strategy.entity;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 此包存放策略服务模块相关的枚举类。
|
||||
* 例如:策略状态枚举、信号类型枚举等。
|
||||
*/
|
||||
package com.trade.strategy.enums;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的过滤器类 (Filter Class)。
|
||||
* <p>
|
||||
* 过滤器类用于在 Servlet 容器处理请求之前或之后执行某些操作,例如请求参数校验、字符编码转换、安全过滤等。
|
||||
* 它们是 Servlet规范的一部分。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.filter;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的处理器类 (Handler Class)。
|
||||
* <p>
|
||||
* 处理器类通常用于处理特定类型的事件、消息或请求,例如消息队列的消费者、WebSocket 处理器、定时任务处理器等。
|
||||
* 它们封装了对特定输入的响应逻辑。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.handler;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 此包存放策略中可能用到的技术指标计算相关的类。
|
||||
* 考虑是否将通用指标计算放到独立的 trade-indicator 模块。
|
||||
*/
|
||||
package com.trade.strategy.indicator;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的拦截器类 (Interceptor Class)。
|
||||
* <p>
|
||||
* 拦截器类用于在 Spring MVC 处理请求的过程中拦截和处理请求,例如权限验证、日志记录、性能监控等。
|
||||
* 它们提供了比过滤器更细粒度的控制,并且可以访问 Spring MVC 的上下文信息。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.interceptor;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的定时任务类 (Job Class)。
|
||||
* <p>
|
||||
* 定时任务类用于执行周期性或预定时间的后台任务,例如数据同步、报表生成、缓存刷新等。
|
||||
* 通常使用 Spring Task 或 Quartz 等框架来实现。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.job;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放事件监听器,例如监听行情事件、订单回报事件等,并根据事件驱动策略执行。
|
||||
*/
|
||||
package com.trade.strategy.listener;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.trade.strategy.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.trade.strategy.entity.StrategyBacktest;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 策略回测记录 Mapper 接口
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@Mapper
|
||||
public interface StrategyBacktestMapper extends BaseMapper<StrategyBacktest> {
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.trade.strategy.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.trade.strategy.entity.StrategyDefinition;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 交易策略定义 Mapper 接口
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@Mapper
|
||||
public interface StrategyDefinitionMapper extends BaseMapper<StrategyDefinition> {
|
||||
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的Mapper接口,用于数据库操作(例如存储策略配置、回测结果等)。
|
||||
*/
|
||||
package com.trade.strategy.mapper;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的领域模型 (Domain Model) 或实体类 (Entity)。
|
||||
* <p>
|
||||
* 这些类通常映射到数据库表结构,代表了系统中的核心业务对象。
|
||||
* 它们包含了对象的属性以及可能的操作方法。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.model;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 策略服务模块主包。
|
||||
*/
|
||||
package com.trade.strategy;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放风险管理相关的类,例如仓位管理、止盈止损逻辑等。
|
||||
*/
|
||||
package com.trade.strategy.risk;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放定时任务相关的类,例如定时执行策略、数据同步等。
|
||||
*/
|
||||
package com.trade.strategy.scheduler;
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.trade.strategy.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.trade.strategy.entity.StrategyBacktest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 策略回测服务接口
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
public interface StrategyBacktestService extends IService<StrategyBacktest> {
|
||||
|
||||
/**
|
||||
* 创建并初始化一个新的策略回测任务
|
||||
*
|
||||
* @param strategyBacktest 回测任务基本信息 (strategyDefinitionId, backtestName, startDate, endDate, initialCapital, commissionRate 必须)
|
||||
* @return 创建成功后的回测任务对象,包含生成的ID和初始状态
|
||||
*/
|
||||
StrategyBacktest createBacktest(StrategyBacktest strategyBacktest);
|
||||
|
||||
/**
|
||||
* 启动一个指定ID的回测任务
|
||||
* (实际回测逻辑可能异步执行)
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @return 更新状态后的回测任务对象 (例如: 状态变为RUNNING)
|
||||
*/
|
||||
StrategyBacktest startBacktest(Long backtestId);
|
||||
|
||||
/**
|
||||
* 更新回测任务的状态和结果
|
||||
* (通常在异步回测任务完成后调用)
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @param status 新的状态 (例如: "COMPLETED", "FAILED")
|
||||
* @param resultDetails 回测结果详情 (JSON格式)
|
||||
* @return 更新后的回测任务对象
|
||||
*/
|
||||
StrategyBacktest updateBacktestStatusAndResult(Long backtestId, String status, String resultDetails);
|
||||
|
||||
/**
|
||||
* 根据ID查询策略回测记录
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @return 回测任务对象,如果不存在则返回null
|
||||
*/
|
||||
StrategyBacktest getBacktestById(Long backtestId);
|
||||
|
||||
/**
|
||||
* 查询指定策略定义的所有回测记录
|
||||
*
|
||||
* @param strategyDefinitionId 策略定义ID
|
||||
* @return 该策略的回测记录列表
|
||||
*/
|
||||
List<StrategyBacktest> getBacktestsByStrategyDefinitionId(Long strategyDefinitionId);
|
||||
|
||||
/**
|
||||
* 查询所有策略回测记录
|
||||
*
|
||||
* @return 所有回测记录列表
|
||||
*/
|
||||
List<StrategyBacktest> getAllBacktests();
|
||||
|
||||
/**
|
||||
* 根据ID删除策略回测记录
|
||||
* (通常只允许删除未开始或已失败的回测)
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
*/
|
||||
void deleteBacktest(Long backtestId);
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.trade.strategy.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.trade.strategy.entity.StrategyDefinition;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 交易策略定义服务接口
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
public interface StrategyDefinitionService extends IService<StrategyDefinition> {
|
||||
|
||||
/**
|
||||
* 创建新的交易策略定义
|
||||
*
|
||||
* @param strategyDefinition 策略定义对象
|
||||
* @return 创建成功后的策略定义对象,包含生成的ID
|
||||
*/
|
||||
StrategyDefinition createStrategy(StrategyDefinition strategyDefinition);
|
||||
|
||||
/**
|
||||
* 更新已有的交易策略定义
|
||||
*
|
||||
* @param strategyDefinition 策略定义对象
|
||||
* @return 更新成功后的策略定义对象
|
||||
*/
|
||||
StrategyDefinition updateStrategy(StrategyDefinition strategyDefinition);
|
||||
|
||||
/**
|
||||
* 根据ID删除交易策略定义
|
||||
*
|
||||
* @param id 策略ID
|
||||
*/
|
||||
void deleteStrategy(Long id);
|
||||
|
||||
/**
|
||||
* 根据ID查询交易策略定义
|
||||
*
|
||||
* @param id 策略ID
|
||||
* @return 策略定义对象,如果不存在则返回null
|
||||
*/
|
||||
StrategyDefinition getStrategyById(Long id);
|
||||
|
||||
/**
|
||||
* 查询所有交易策略定义
|
||||
*
|
||||
* @return 策略定义列表
|
||||
*/
|
||||
List<StrategyDefinition> getAllStrategies();
|
||||
|
||||
/**
|
||||
* 根据策略名称查询交易策略定义
|
||||
*
|
||||
* @param name 策略名称
|
||||
* @return 策略定义对象,如果不存在则返回null
|
||||
*/
|
||||
StrategyDefinition getStrategyByName(String name);
|
||||
|
||||
/**
|
||||
* 根据策略类型查询交易策略定义
|
||||
*
|
||||
* @param type 策略类型
|
||||
* @return 符合类型的策略定义列表
|
||||
*/
|
||||
List<StrategyDefinition> getStrategiesByType(String type);
|
||||
|
||||
/**
|
||||
* 根据策略状态查询交易策略定义
|
||||
*
|
||||
* @param status 策略状态
|
||||
* @return 符合状态的策略定义列表
|
||||
*/
|
||||
List<StrategyDefinition> getStrategiesByStatus(String status);
|
||||
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package com.trade.strategy.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.trade.strategy.entity.StrategyBacktest;
|
||||
import com.trade.strategy.entity.StrategyDefinition;
|
||||
import com.trade.strategy.mapper.StrategyBacktestMapper;
|
||||
import com.trade.strategy.service.StrategyBacktestService;
|
||||
import com.trade.strategy.service.StrategyDefinitionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 策略回测服务实现类
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@Service
|
||||
public class StrategyBacktestServiceImpl extends ServiceImpl<StrategyBacktestMapper, StrategyBacktest> implements StrategyBacktestService {
|
||||
|
||||
@Autowired
|
||||
private StrategyDefinitionService strategyDefinitionService; // 用于校验策略定义是否存在
|
||||
|
||||
// 假设有一个异步执行回测的组件,这里仅作演示
|
||||
// @Autowired
|
||||
// private BacktestExecutionEngine backtestExecutionEngine;
|
||||
|
||||
/**
|
||||
* 创建并初始化一个新的策略回测任务
|
||||
*
|
||||
* @param strategyBacktest 回测任务基本信息
|
||||
* @return 创建成功后的回测任务对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public StrategyBacktest createBacktest(StrategyBacktest strategyBacktest) {
|
||||
// 参数校验
|
||||
if (strategyBacktest.getStrategyDefinitionId() == null) {
|
||||
throw new IllegalArgumentException("策略定义ID不能为空");
|
||||
}
|
||||
StrategyDefinition definition = strategyDefinitionService.getStrategyById(strategyBacktest.getStrategyDefinitionId());
|
||||
if (definition == null) {
|
||||
throw new IllegalArgumentException("指定的策略定义不存在: ID " + strategyBacktest.getStrategyDefinitionId());
|
||||
}
|
||||
if (!StringUtils.hasText(strategyBacktest.getBacktestName())) {
|
||||
throw new IllegalArgumentException("回测名称不能为空");
|
||||
}
|
||||
if (strategyBacktest.getStartDate() == null || strategyBacktest.getEndDate() == null) {
|
||||
throw new IllegalArgumentException("回测开始或结束日期不能为空");
|
||||
}
|
||||
if (strategyBacktest.getStartDate().isAfter(strategyBacktest.getEndDate())) {
|
||||
throw new IllegalArgumentException("回测开始日期不能晚于结束日期");
|
||||
}
|
||||
if (strategyBacktest.getInitialCapital() == null || strategyBacktest.getInitialCapital().doubleValue() <= 0) {
|
||||
throw new IllegalArgumentException("初始资金必须大于0");
|
||||
}
|
||||
// 手续费率可以为0
|
||||
if (strategyBacktest.getCommissionRate() == null || strategyBacktest.getCommissionRate().doubleValue() < 0) {
|
||||
strategyBacktest.setCommissionRate(java.math.BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
strategyBacktest.setStatus("PENDING"); // 初始状态为待处理
|
||||
strategyBacktest.setCreateTime(LocalDateTime.now());
|
||||
strategyBacktest.setUpdateTime(LocalDateTime.now());
|
||||
this.save(strategyBacktest);
|
||||
return strategyBacktest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动一个指定ID的回测任务
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @return 更新状态后的回测任务对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public StrategyBacktest startBacktest(Long backtestId) {
|
||||
StrategyBacktest backtest = getBacktestById(backtestId);
|
||||
if (backtest == null) {
|
||||
throw new IllegalArgumentException("未找到要启动的回测任务,ID: " + backtestId);
|
||||
}
|
||||
if (!"PENDING".equals(backtest.getStatus())) {
|
||||
throw new IllegalStateException("回测任务当前状态为 " + backtest.getStatus() + ",无法启动。");
|
||||
}
|
||||
|
||||
backtest.setStatus("RUNNING");
|
||||
backtest.setUpdateTime(LocalDateTime.now());
|
||||
this.updateById(backtest);
|
||||
|
||||
// 实际场景中,这里会触发异步回测引擎执行回测
|
||||
// backtestExecutionEngine.execute(backtest);
|
||||
// log.info("策略回测任务 [{}] 已启动", backtestId);
|
||||
|
||||
return backtest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新回测任务的状态和结果
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @param status 新的状态
|
||||
* @param resultDetails 回测结果详情
|
||||
* @return 更新后的回测任务对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public StrategyBacktest updateBacktestStatusAndResult(Long backtestId, String status, String resultDetails) {
|
||||
StrategyBacktest backtest = getBacktestById(backtestId);
|
||||
if (backtest == null) {
|
||||
throw new IllegalArgumentException("未找到要更新的回测任务,ID: " + backtestId);
|
||||
}
|
||||
|
||||
backtest.setStatus(status);
|
||||
backtest.setResultDetails(resultDetails);
|
||||
backtest.setUpdateTime(LocalDateTime.now());
|
||||
this.updateById(backtest);
|
||||
return backtest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询策略回测记录
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
* @return 回测任务对象
|
||||
*/
|
||||
@Override
|
||||
public StrategyBacktest getBacktestById(Long backtestId) {
|
||||
return this.getById(backtestId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定策略定义的所有回测记录
|
||||
*
|
||||
* @param strategyDefinitionId 策略定义ID
|
||||
* @return 回测记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyBacktest> getBacktestsByStrategyDefinitionId(Long strategyDefinitionId) {
|
||||
if (strategyDefinitionId == null) {
|
||||
return List.of();
|
||||
}
|
||||
return this.list(new QueryWrapper<StrategyBacktest>().eq("strategy_definition_id", strategyDefinitionId)
|
||||
.orderByDesc("create_time")); // 按创建时间降序
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有策略回测记录
|
||||
*
|
||||
* @return 所有回测记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyBacktest> getAllBacktests() {
|
||||
return this.list(new QueryWrapper<StrategyBacktest>().orderByDesc("create_time"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID删除策略回测记录
|
||||
*
|
||||
* @param backtestId 回测任务ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteBacktest(Long backtestId) {
|
||||
StrategyBacktest backtest = getBacktestById(backtestId);
|
||||
if (backtest == null) {
|
||||
throw new IllegalArgumentException("未找到要删除的回测任务,ID: " + backtestId);
|
||||
}
|
||||
// 通常只允许删除 PENDING 或 FAILED 的回测,或者根据业务需求调整
|
||||
if ("RUNNING".equals(backtest.getStatus()) || "COMPLETED".equals(backtest.getStatus())) {
|
||||
// throw new IllegalStateException("无法删除正在运行或已完成的回测任务。");
|
||||
}
|
||||
this.removeById(backtestId);
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
package com.trade.strategy.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.trade.strategy.entity.StrategyDefinition;
|
||||
import com.trade.strategy.mapper.StrategyDefinitionMapper;
|
||||
import com.trade.strategy.service.StrategyDefinitionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 交易策略定义服务实现类
|
||||
*
|
||||
* @author AI Assistant
|
||||
*/
|
||||
@Service
|
||||
public class StrategyDefinitionServiceImpl extends ServiceImpl<StrategyDefinitionMapper, StrategyDefinition> implements StrategyDefinitionService {
|
||||
|
||||
/**
|
||||
* 创建新的交易策略定义
|
||||
*
|
||||
* @param strategyDefinition 策略定义对象
|
||||
* @return 创建成功后的策略定义对象,包含生成的ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public StrategyDefinition createStrategy(StrategyDefinition strategyDefinition) {
|
||||
// 可以在这里添加校验逻辑,例如名称是否唯一等
|
||||
if (!StringUtils.hasText(strategyDefinition.getName())) {
|
||||
throw new IllegalArgumentException("策略名称不能为空");
|
||||
}
|
||||
StrategyDefinition existing = getStrategyByName(strategyDefinition.getName());
|
||||
if (existing != null) {
|
||||
throw new IllegalArgumentException("策略名称已存在: " + strategyDefinition.getName());
|
||||
}
|
||||
|
||||
strategyDefinition.setCreateTime(LocalDateTime.now());
|
||||
strategyDefinition.setUpdateTime(LocalDateTime.now());
|
||||
// 默认状态可以设置为 DRAFT
|
||||
if (!StringUtils.hasText(strategyDefinition.getStatus())){
|
||||
strategyDefinition.setStatus("DRAFT");
|
||||
}
|
||||
this.save(strategyDefinition);
|
||||
return strategyDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新已有的交易策略定义
|
||||
*
|
||||
* @param strategyDefinition 策略定义对象
|
||||
* @return 更新成功后的策略定义对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public StrategyDefinition updateStrategy(StrategyDefinition strategyDefinition) {
|
||||
if (strategyDefinition.getId() == null) {
|
||||
throw new IllegalArgumentException("更新策略时,策略ID不能为空");
|
||||
}
|
||||
StrategyDefinition existing = getById(strategyDefinition.getId());
|
||||
if (existing == null) {
|
||||
throw new IllegalArgumentException("未找到要更新的策略,ID: " + strategyDefinition.getId());
|
||||
}
|
||||
|
||||
// 如果名称被修改,需要检查新名称是否已存在(排除自身)
|
||||
if (StringUtils.hasText(strategyDefinition.getName()) && !strategyDefinition.getName().equals(existing.getName())){
|
||||
StrategyDefinition byNewName = getStrategyByName(strategyDefinition.getName());
|
||||
if(byNewName != null && !byNewName.getId().equals(strategyDefinition.getId())){
|
||||
throw new IllegalArgumentException("策略名称已存在: " + strategyDefinition.getName());
|
||||
}
|
||||
}
|
||||
|
||||
strategyDefinition.setUpdateTime(LocalDateTime.now());
|
||||
this.updateById(strategyDefinition);
|
||||
return getById(strategyDefinition.getId()); // 返回更新后的完整对象
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID删除交易策略定义
|
||||
*
|
||||
* @param id 策略ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteStrategy(Long id) {
|
||||
if (id == null) {
|
||||
throw new IllegalArgumentException("删除策略时,策略ID不能为空");
|
||||
}
|
||||
if (getById(id) == null) {
|
||||
throw new IllegalArgumentException("未找到要删除的策略,ID: " + id);
|
||||
}
|
||||
this.removeById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询交易策略定义
|
||||
*
|
||||
* @param id 策略ID
|
||||
* @return 策略定义对象,如果不存在则返回null
|
||||
*/
|
||||
@Override
|
||||
public StrategyDefinition getStrategyById(Long id) {
|
||||
return this.getById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有交易策略定义
|
||||
*
|
||||
* @return 策略定义列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyDefinition> getAllStrategies() {
|
||||
return this.list();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略名称查询交易策略定义
|
||||
*
|
||||
* @param name 策略名称
|
||||
* @return 策略定义对象,如果不存在则返回null
|
||||
*/
|
||||
@Override
|
||||
public StrategyDefinition getStrategyByName(String name) {
|
||||
if (!StringUtils.hasText(name)) {
|
||||
return null;
|
||||
}
|
||||
return this.getOne(new QueryWrapper<StrategyDefinition>().eq("name", name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略类型查询交易策略定义
|
||||
*
|
||||
* @param type 策略类型
|
||||
* @return 符合类型的策略定义列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyDefinition> getStrategiesByType(String type) {
|
||||
if (!StringUtils.hasText(type)) {
|
||||
return this.list(); // 如果类型为空,返回所有
|
||||
}
|
||||
return this.list(new QueryWrapper<StrategyDefinition>().eq("type", type));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略状态查询交易策略定义
|
||||
*
|
||||
* @param status 策略状态
|
||||
* @return 符合状态的策略定义列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyDefinition> getStrategiesByStatus(String status) {
|
||||
if (!StringUtils.hasText(status)) {
|
||||
return this.list(); // 如果状态为空,返回所有
|
||||
}
|
||||
return this.list(new QueryWrapper<StrategyDefinition>().eq("status", status));
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块Service接口的实现类。
|
||||
*/
|
||||
package com.trade.strategy.service.impl;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的Service层,负责业务逻辑处理,例如策略的创建、执行、回测等。
|
||||
*/
|
||||
package com.trade.strategy.service;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 此包包含策略服务模块的工具类 (Utility Class)。
|
||||
* <p>
|
||||
* 工具类提供各种通用的辅助方法,例如日期时间处理、字符串操作、加解密、文件操作等。
|
||||
* 它们通常包含静态方法,方便在应用程序的各个部分调用。
|
||||
* </p>
|
||||
*/
|
||||
package com.trade.strategy.util;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的工具类。
|
||||
*/
|
||||
package com.trade.strategy.utils;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放策略服务模块的视图对象 (VO)。
|
||||
*/
|
||||
package com.trade.strategy.vo;
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package com.yudao.module.strategy.controller.admin.execution;
|
||||
|
||||
import com.yudao.framework.common.pojo.CommonResult;
|
||||
import com.yudao.framework.common.pojo.PageResult;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.*;
|
||||
import com.yudao.module.strategy.convert.execution.StrategyExecutionConvert;
|
||||
import com.yudao.module.strategy.dal.dataobject.execution.StrategyExecution;
|
||||
import com.yudao.module.strategy.service.execution.StrategyExecutionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 策略执行")
|
||||
@RestController
|
||||
@RequestMapping("/strategy/execution")
|
||||
@Validated
|
||||
public class StrategyExecutionController {
|
||||
|
||||
@Resource
|
||||
private StrategyExecutionService strategyExecutionService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建策略执行")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:create')")
|
||||
public CommonResult<Long> createStrategyExecution(@Valid @RequestBody StrategyExecutionCreateReqVO createReqVO) {
|
||||
return success(strategyExecutionService.createStrategyExecution(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新策略执行")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:update')")
|
||||
public CommonResult<Boolean> updateStrategyExecution(@Valid @RequestBody StrategyExecutionUpdateReqVO updateReqVO) {
|
||||
strategyExecutionService.updateStrategyExecution(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/start")
|
||||
@Operation(summary = "启动策略执行")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:start')")
|
||||
public CommonResult<Boolean> startStrategyExecution(@RequestParam("id") Long id) {
|
||||
strategyExecutionService.startStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/pause")
|
||||
@Operation(summary = "暂停策略执行")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:pause')")
|
||||
public CommonResult<Boolean> pauseStrategyExecution(@RequestParam("id") Long id) {
|
||||
strategyExecutionService.pauseStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/stop")
|
||||
@Operation(summary = "停止策略执行")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:stop')")
|
||||
public CommonResult<Boolean> stopStrategyExecution(@RequestParam("id") Long id) {
|
||||
strategyExecutionService.stopStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除策略执行")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:delete')")
|
||||
public CommonResult<Boolean> deleteStrategyExecution(@RequestParam("id") Long id) {
|
||||
strategyExecutionService.deleteStrategyExecution(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得策略执行")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:query')")
|
||||
public CommonResult<StrategyExecutionRespVO> getStrategyExecution(@RequestParam("id") Long id) {
|
||||
StrategyExecution execution = strategyExecutionService.getStrategyExecution(id);
|
||||
return success(StrategyExecutionConvert.INSTANCE.convert(execution));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得策略执行列表")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:query')")
|
||||
public CommonResult<List<StrategyExecutionRespVO>> getStrategyExecutionList(@RequestParam("ids") Collection<Long> ids) {
|
||||
List<StrategyExecution> list = strategyExecutionService.getStrategyExecutionList(ids);
|
||||
return success(StrategyExecutionConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得策略执行分页")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:query')")
|
||||
public CommonResult<PageResult<StrategyExecutionRespVO>> getStrategyExecutionPage(@Valid StrategyExecutionPageReqVO pageVO) {
|
||||
PageResult<StrategyExecution> pageResult = strategyExecutionService.getStrategyExecutionPage(pageVO);
|
||||
return success(StrategyExecutionConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-definition")
|
||||
@Operation(summary = "根据策略定义ID获得策略执行列表")
|
||||
@Parameter(name = "strategyDefinitionId", description = "策略定义ID", required = true, example = "100")
|
||||
@PreAuthorize("@ss.hasPermission('strategy:execution:query')")
|
||||
public CommonResult<List<StrategyExecutionRespVO>> getStrategyExecutionsByDefinitionId(@RequestParam("strategyDefinitionId") Long strategyDefinitionId) {
|
||||
List<StrategyExecution> list = strategyExecutionService.getStrategyExecutionsByDefinitionId(strategyDefinitionId);
|
||||
return success(StrategyExecutionConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.yudao.module.strategy.controller.admin.execution.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 策略执行创建 Request VO")
|
||||
@Data
|
||||
public class StrategyExecutionCreateReqVO {
|
||||
|
||||
@Schema(description = "策略定义ID", required = true, example = "1024")
|
||||
@NotNull(message = "策略定义ID不能为空")
|
||||
private Long strategyDefinitionId;
|
||||
|
||||
@Schema(description = "执行名称", required = true, example = "MA策略实盘执行-20240101")
|
||||
@NotEmpty(message = "执行名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "执行类型(1:实盘交易,2:模拟交易)", required = true, example = "1")
|
||||
@NotNull(message = "执行类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "初始资金", required = true, example = "100000.00")
|
||||
@NotNull(message = "初始资金不能为空")
|
||||
private BigDecimal initialCapital;
|
||||
|
||||
@Schema(description = "手续费率", required = true, example = "0.0003")
|
||||
@NotNull(message = "手续费率不能为空")
|
||||
private BigDecimal commissionRate;
|
||||
|
||||
@Schema(description = "执行参数(JSON格式)", example = "{\"stopLoss\": 0.05}")
|
||||
private String parameters;
|
||||
|
||||
@Schema(description = "备注", example = "测试执行")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.yudao.module.strategy.controller.admin.execution.vo;
|
||||
|
||||
import com.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 策略执行分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class StrategyExecutionPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "策略定义ID", example = "1024")
|
||||
private Long strategyDefinitionId;
|
||||
|
||||
@Schema(description = "执行名称", example = "MA策略")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "执行类型(1:实盘交易,2:模拟交易)", example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "执行状态(0:未开始,1:运行中,2:已暂停,3:已停止,4:已完成,5:执行错误)", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "开始执行时间范围 - 开始")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] startTime;
|
||||
|
||||
@Schema(description = "创建时间范围 - 开始")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.yudao.module.strategy.controller.admin.execution.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 策略执行 Response VO")
|
||||
@Data
|
||||
public class StrategyExecutionRespVO {
|
||||
|
||||
@Schema(description = "执行记录ID", required = true, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "策略定义ID", required = true, example = "1024")
|
||||
private Long strategyDefinitionId;
|
||||
|
||||
@Schema(description = "执行名称", required = true, example = "MA策略实盘执行-20240101")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "执行类型(1:实盘交易,2:模拟交易)", required = true, example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "初始资金", required = true, example = "100000.00")
|
||||
private BigDecimal initialCapital;
|
||||
|
||||
@Schema(description = "当前资金", required = true, example = "105000.00")
|
||||
private BigDecimal currentCapital;
|
||||
|
||||
@Schema(description = "总盈亏金额", required = true, example = "5000.00")
|
||||
private BigDecimal totalProfitLoss;
|
||||
|
||||
@Schema(description = "总盈亏比例", required = true, example = "0.05")
|
||||
private BigDecimal totalProfitLossRatio;
|
||||
|
||||
@Schema(description = "手续费率", required = true, example = "0.0003")
|
||||
private BigDecimal commissionRate;
|
||||
|
||||
@Schema(description = "执行状态(0:未开始,1:运行中,2:已暂停,3:已停止,4:已完成,5:执行错误)", required = true, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "错误信息", example = "策略执行异常:无法获取行情数据")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "开始执行时间", example = "2024-01-01 09:30:00")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@Schema(description = "结束执行时间", example = "2024-01-01 15:00:00")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
@Schema(description = "执行参数(JSON格式)", example = "{\"stopLoss\": 0.05}")
|
||||
private String parameters;
|
||||
|
||||
@Schema(description = "备注", example = "测试执行")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", required = true)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间", required = true)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.yudao.module.strategy.controller.admin.execution.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 策略执行更新 Request VO")
|
||||
@Data
|
||||
public class StrategyExecutionUpdateReqVO {
|
||||
|
||||
@Schema(description = "执行记录ID", required = true, example = "1")
|
||||
@NotNull(message = "执行记录ID不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "执行名称", example = "MA策略实盘执行-20240101-V2")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "执行类型(1:实盘交易,2:模拟交易)", example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "初始资金", example = "120000.00")
|
||||
private BigDecimal initialCapital;
|
||||
|
||||
@Schema(description = "手续费率", example = "0.00025")
|
||||
private BigDecimal commissionRate;
|
||||
|
||||
@Schema(description = "执行参数(JSON格式)", example = "{\"stopLoss\": 0.06, \"takeProfit\": 0.1}")
|
||||
private String parameters;
|
||||
|
||||
@Schema(description = "备注", example = "更新执行参数")
|
||||
private String remark;
|
||||
|
||||
// 注意:通常不直接通过API更新执行状态、当前资金、盈亏等,这些应由系统内部逻辑管理
|
||||
// 如果确实需要手动调整状态(例如管理员干预),可以单独提供接口或在此VO中添加并谨慎处理
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.yudao.module.strategy.convert.execution;
|
||||
|
||||
import com.yudao.framework.common.pojo.PageResult;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionCreateReqVO;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionRespVO;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionUpdateReqVO;
|
||||
import com.yudao.module.strategy.dal.dataobject.execution.StrategyExecution;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 策略执行 Convert
|
||||
*/
|
||||
@Mapper
|
||||
public interface StrategyExecutionConvert {
|
||||
|
||||
StrategyExecutionConvert INSTANCE = Mappers.getMapper(StrategyExecutionConvert.class);
|
||||
|
||||
/**
|
||||
* 创建请求 VO 转换为 DO
|
||||
*/
|
||||
StrategyExecution convert(StrategyExecutionCreateReqVO bean);
|
||||
|
||||
/**
|
||||
* 更新请求 VO 转换为 DO
|
||||
*/
|
||||
StrategyExecution convert(StrategyExecutionUpdateReqVO bean);
|
||||
|
||||
/**
|
||||
* DO 转换为响应 VO
|
||||
*/
|
||||
StrategyExecutionRespVO convert(StrategyExecution bean);
|
||||
|
||||
/**
|
||||
* DO 列表转换为响应 VO 列表
|
||||
*/
|
||||
List<StrategyExecutionRespVO> convertList(List<StrategyExecution> list);
|
||||
|
||||
/**
|
||||
* 分页结果转换
|
||||
*/
|
||||
PageResult<StrategyExecutionRespVO> convertPage(PageResult<StrategyExecution> page);
|
||||
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.yudao.module.strategy.dal.dataobject.execution;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 策略执行记录 DO
|
||||
*/
|
||||
@TableName("strategy_execution")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class StrategyExecution extends BaseDO {
|
||||
|
||||
/**
|
||||
* 执行记录ID
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 策略定义ID
|
||||
*/
|
||||
private Long strategyDefinitionId;
|
||||
|
||||
/**
|
||||
* 执行名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 执行类型(1:实盘交易,2:模拟交易)
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 初始资金
|
||||
*/
|
||||
private BigDecimal initialCapital;
|
||||
|
||||
/**
|
||||
* 当前资金
|
||||
*/
|
||||
private BigDecimal currentCapital;
|
||||
|
||||
/**
|
||||
* 总盈亏金额
|
||||
*/
|
||||
private BigDecimal totalProfitLoss;
|
||||
|
||||
/**
|
||||
* 总盈亏比例
|
||||
*/
|
||||
private BigDecimal totalProfitLossRatio;
|
||||
|
||||
/**
|
||||
* 手续费率
|
||||
*/
|
||||
private BigDecimal commissionRate;
|
||||
|
||||
/**
|
||||
* 执行状态(0:未开始,1:运行中,2:已暂停,3:已停止,4:已完成,5:执行错误)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 开始执行时间
|
||||
*/
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 结束执行时间
|
||||
*/
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 执行参数(JSON格式)
|
||||
*/
|
||||
private String parameters;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.yudao.module.strategy.dal.mysql.execution;
|
||||
|
||||
import com.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.yudao.module.strategy.dal.dataobject.execution.StrategyExecution;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 策略执行记录 Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface StrategyExecutionMapper extends BaseMapperX<StrategyExecution> {
|
||||
|
||||
// 可以在此定义特定的查询方法,例如根据策略定义ID查询执行记录等
|
||||
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package com.yudao.module.strategy.service.execution;
|
||||
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionCreateReqVO;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionPageReqVO;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionUpdateReqVO;
|
||||
import com.yudao.module.strategy.dal.dataobject.execution.StrategyExecution;
|
||||
import com.yudao.framework.common.pojo.PageResult;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 策略执行 Service 接口
|
||||
*/
|
||||
public interface StrategyExecutionService {
|
||||
|
||||
/**
|
||||
* 创建策略执行记录
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createStrategyExecution(@Valid StrategyExecutionCreateReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新策略执行记录
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateStrategyExecution(@Valid StrategyExecutionUpdateReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 启动策略执行
|
||||
*
|
||||
* @param id 策略执行编号
|
||||
*/
|
||||
void startStrategyExecution(Long id);
|
||||
|
||||
/**
|
||||
* 暂停策略执行
|
||||
*
|
||||
* @param id 策略执行编号
|
||||
*/
|
||||
void pauseStrategyExecution(Long id);
|
||||
|
||||
/**
|
||||
* 停止策略执行
|
||||
*
|
||||
* @param id 策略执行编号
|
||||
*/
|
||||
void stopStrategyExecution(Long id);
|
||||
|
||||
/**
|
||||
* 删除策略执行记录
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deleteStrategyExecution(Long id);
|
||||
|
||||
/**
|
||||
* 获得策略执行记录
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 策略执行记录
|
||||
*/
|
||||
StrategyExecution getStrategyExecution(Long id);
|
||||
|
||||
/**
|
||||
* 获得策略执行记录列表
|
||||
*
|
||||
* @param ids 编号列表
|
||||
* @return 策略执行记录列表
|
||||
*/
|
||||
List<StrategyExecution> getStrategyExecutionList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得策略执行记录分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 策略执行记录分页
|
||||
*/
|
||||
PageResult<StrategyExecution> getStrategyExecutionPage(StrategyExecutionPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 根据策略定义ID查询执行记录列表
|
||||
*
|
||||
* @param strategyDefinitionId 策略定义ID
|
||||
* @return 策略执行记录列表
|
||||
*/
|
||||
List<StrategyExecution> getStrategyExecutionsByDefinitionId(Long strategyDefinitionId);
|
||||
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
package com.yudao.module.strategy.service.execution;
|
||||
|
||||
import com.yudao.framework.common.pojo.PageResult;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionCreateReqVO;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionPageReqVO;
|
||||
import com.yudao.module.strategy.controller.admin.execution.vo.StrategyExecutionUpdateReqVO;
|
||||
import com.yudao.module.strategy.convert.execution.StrategyExecutionConvert;
|
||||
import com.yudao.module.strategy.dal.dataobject.execution.StrategyExecution;
|
||||
import com.yudao.module.strategy.dal.mysql.execution.StrategyExecutionMapper;
|
||||
import com.yudao.module.strategy.enums.StrategyExecutionStatusEnum;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.yudao.module.strategy.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 策略执行 Service 实现类
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class StrategyExecutionServiceImpl implements StrategyExecutionService {
|
||||
|
||||
@Resource
|
||||
private StrategyExecutionMapper strategyExecutionMapper;
|
||||
|
||||
/**
|
||||
* 创建策略执行记录
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
@Override
|
||||
public Long createStrategyExecution(StrategyExecutionCreateReqVO createReqVO) {
|
||||
// 校验策略定义是否存在等前置条件 (根据实际业务补充)
|
||||
// ...
|
||||
|
||||
StrategyExecution strategyExecution = StrategyExecutionConvert.INSTANCE.convert(createReqVO);
|
||||
strategyExecution.setStatus(StrategyExecutionStatusEnum.NOT_STARTED.getStatus()); // 初始状态为未开始
|
||||
strategyExecutionMapper.insert(strategyExecution);
|
||||
return strategyExecution.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新策略执行记录
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
@Override
|
||||
public void updateStrategyExecution(StrategyExecutionUpdateReqVO updateReqVO) {
|
||||
validateStrategyExecutionExists(updateReqVO.getId());
|
||||
StrategyExecution updateObj = StrategyExecutionConvert.INSTANCE.convert(updateReqVO);
|
||||
strategyExecutionMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动策略执行
|
||||
*
|
||||
* @param id 策略执行编号
|
||||
*/
|
||||
@Override
|
||||
public void startStrategyExecution(Long id) {
|
||||
StrategyExecution execution = validateStrategyExecutionExists(id);
|
||||
if (!StrategyExecutionStatusEnum.NOT_STARTED.getStatus().equals(execution.getStatus()) &&
|
||||
!StrategyExecutionStatusEnum.PAUSED.getStatus().equals(execution.getStatus()) &&
|
||||
!StrategyExecutionStatusEnum.ERROR.getStatus().equals(execution.getStatus())) {
|
||||
throw exception(STRATEGY_EXECUTION_CANNOT_START, execution.getStatus());
|
||||
}
|
||||
// 实际启动逻辑,可能需要与交易引擎交互
|
||||
// ...
|
||||
StrategyExecution updateObj = new StrategyExecution();
|
||||
updateObj.setId(id);
|
||||
updateObj.setStatus(StrategyExecutionStatusEnum.RUNNING.getStatus());
|
||||
updateObj.setStartTime(LocalDateTime.now()); // 记录开始时间
|
||||
strategyExecutionMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停策略执行
|
||||
*
|
||||
* @param id 策略执行编号
|
||||
*/
|
||||
@Override
|
||||
public void pauseStrategyExecution(Long id) {
|
||||
StrategyExecution execution = validateStrategyExecutionExists(id);
|
||||
if (!StrategyExecutionStatusEnum.RUNNING.getStatus().equals(execution.getStatus())) {
|
||||
throw exception(STRATEGY_EXECUTION_CANNOT_PAUSE, execution.getStatus());
|
||||
}
|
||||
// 实际暂停逻辑
|
||||
// ...
|
||||
StrategyExecution updateObj = new StrategyExecution();
|
||||
updateObj.setId(id);
|
||||
updateObj.setStatus(StrategyExecutionStatusEnum.PAUSED.getStatus());
|
||||
strategyExecutionMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止策略执行
|
||||
*
|
||||
* @param id 策略执行编号
|
||||
*/
|
||||
@Override
|
||||
public void stopStrategyExecution(Long id) {
|
||||
StrategyExecution execution = validateStrategyExecutionExists(id);
|
||||
if (StrategyExecutionStatusEnum.COMPLETED.getStatus().equals(execution.getStatus()) ||
|
||||
StrategyExecutionStatusEnum.STOPPED.getStatus().equals(execution.getStatus())) {
|
||||
throw exception(STRATEGY_EXECUTION_ALREADY_STOPPED_OR_COMPLETED, execution.getStatus());
|
||||
}
|
||||
// 实际停止逻辑,可能需要进行一些清理工作
|
||||
// ...
|
||||
StrategyExecution updateObj = new StrategyExecution();
|
||||
updateObj.setId(id);
|
||||
updateObj.setStatus(StrategyExecutionStatusEnum.STOPPED.getStatus());
|
||||
updateObj.setEndTime(LocalDateTime.now()); // 记录结束时间
|
||||
strategyExecutionMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除策略执行记录
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
@Override
|
||||
public void deleteStrategyExecution(Long id) {
|
||||
validateStrategyExecutionExists(id);
|
||||
// 需要考虑是否允许删除运行中的策略等
|
||||
strategyExecutionMapper.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验策略执行记录是否存在
|
||||
*
|
||||
* @param id 策略执行ID
|
||||
* @return 策略执行记录
|
||||
*/
|
||||
private StrategyExecution validateStrategyExecutionExists(Long id) {
|
||||
StrategyExecution execution = strategyExecutionMapper.selectById(id);
|
||||
if (execution == null) {
|
||||
throw exception(STRATEGY_EXECUTION_NOT_EXISTS);
|
||||
}
|
||||
return execution;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得策略执行记录
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 策略执行记录
|
||||
*/
|
||||
@Override
|
||||
public StrategyExecution getStrategyExecution(Long id) {
|
||||
return strategyExecutionMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得策略执行记录列表
|
||||
*
|
||||
* @param ids 编号列表
|
||||
* @return 策略执行记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyExecution> getStrategyExecutionList(Collection<Long> ids) {
|
||||
return strategyExecutionMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得策略执行记录分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 策略执行记录分页
|
||||
*/
|
||||
@Override
|
||||
public PageResult<StrategyExecution> getStrategyExecutionPage(StrategyExecutionPageReqVO pageReqVO) {
|
||||
return strategyExecutionMapper.selectPage(pageReqVO, StrategyExecutionConvert.INSTANCE.convert(pageReqVO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略定义ID查询执行记录列表
|
||||
*
|
||||
* @param strategyDefinitionId 策略定义ID
|
||||
* @return 策略执行记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<StrategyExecution> getStrategyExecutionsByDefinitionId(Long strategyDefinitionId) {
|
||||
return strategyExecutionMapper.selectList(StrategyExecution::getStrategyDefinitionId, strategyDefinitionId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
server:
|
||||
port: 8007
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
application:
|
||||
name: trade-strategy
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
@@ -0,0 +1,11 @@
|
||||
server:
|
||||
port: 8007
|
||||
spring:
|
||||
profiles:
|
||||
active: prod
|
||||
application:
|
||||
name: trade-strategy
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
@@ -0,0 +1,11 @@
|
||||
server:
|
||||
port: 8007
|
||||
spring:
|
||||
profiles:
|
||||
active: test
|
||||
application:
|
||||
name: trade-strategy
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
@@ -0,0 +1,103 @@
|
||||
server:
|
||||
port: 8083 # 策略服务端口
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: trade-strategy # 应用名称
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848 # Nacos 服务注册中心地址
|
||||
namespace: trade_dev # Nacos 命名空间
|
||||
group: DEFAULT_GROUP # Nacos 分组
|
||||
config:
|
||||
server-addr: 127.0.0.1:8848 # Nacos 配置中心地址
|
||||
namespace: trade_dev # Nacos 命名空间
|
||||
group: DEFAULT_GROUP # Nacos 分组
|
||||
file-extension: yml # 配置文件格式
|
||||
shared-configs: # 共享配置
|
||||
- data-id: application-common.yml # 通用配置
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
- data-id: trade-redis.yml # Redis 配置
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
- data-id: trade-mybatis-plus.yml # MyBatis Plus 配置
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
# # Sentinel 配置 (按需开启)
|
||||
# sentinel:
|
||||
# transport:
|
||||
# dashboard: localhost:8080 # Sentinel 控制台地址
|
||||
# port: 8719 # Sentinel 客户端与控制台通信端口
|
||||
# datasource:
|
||||
# ds1:
|
||||
# nacos:
|
||||
# server-addr: ${spring.cloud.nacos.config.server-addr}
|
||||
# namespace: ${spring.cloud.nacos.config.namespace}
|
||||
# dataId: ${spring.application.name}-sentinel-rules
|
||||
# groupId: SENTINEL_GROUP
|
||||
# data-type: json
|
||||
# rule-type: flow
|
||||
|
||||
# Seata 配置 (按需开启)
|
||||
#seata:
|
||||
# tx-service-group: trade_tx_group # 事务组名称,需要与 Seata Server 配置一致
|
||||
# service:
|
||||
# vgroup-mapping:
|
||||
# trade_tx_group: default # 事务组与 Seata Server 实例的映射关系
|
||||
# registry:
|
||||
# type: nacos
|
||||
# nacos:
|
||||
# server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
# namespace: ${spring.cloud.nacos.discovery.namespace}
|
||||
# group: SEATA_GROUP
|
||||
# config:
|
||||
# type: nacos
|
||||
# nacos:
|
||||
# server-addr: ${spring.cloud.nacos.config.server-addr}
|
||||
# namespace: ${spring.cloud.nacos.config.namespace}
|
||||
# group: SEATA_GROUP
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.trade.strategy: debug
|
||||
org.springframework: info
|
||||
org.apache.ibatis: info
|
||||
|
||||
# Actuator 配置
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: '*' # 开放所有端点,生产环境建议按需开放
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always # 显示健康检查详情
|
||||
|
||||
# MyBatis Plus 配置 (如果 trade-mybatis-plus.yml 中未配置或需要覆盖)
|
||||
#mybatis-plus:
|
||||
# mapper-locations: classpath*:/mapper/**/*.xml # Mapper XML 文件位置
|
||||
# global-config:
|
||||
# db-config:
|
||||
# id-type: assign_id # ID 生成策略
|
||||
|
||||
# 策略引擎相关配置 (示例)
|
||||
strategy:
|
||||
engine:
|
||||
thread-pool-size: 10 # 策略执行线程池大小
|
||||
data-source:
|
||||
type: local # 数据源类型,例如: local, remote_api, message_queue
|
||||
# ... 其他数据源相关配置
|
||||
|
||||
# 开放 API 文档配置 (如果需要)
|
||||
#springdoc:
|
||||
# api-docs:
|
||||
# path: /v3/api-docs
|
||||
# swagger-ui:
|
||||
# path: /swagger-ui.html
|
||||
# display-request-duration: true
|
||||
# groups-order: DESC
|
||||
# operations-sorter: alpha
|
||||
# tags-sorter: alpha
|
||||
@@ -0,0 +1,24 @@
|
||||
# Spring Cloud Alibaba Nacos Config
|
||||
spring:
|
||||
application:
|
||||
name: trade-strategy # 应用名称,必须与 Nacos 中的 Data ID 对应
|
||||
cloud:
|
||||
nacos:
|
||||
config:
|
||||
server-addr: 127.0.0.1:8848 # Nacos Server 地址
|
||||
namespace: trade_dev # Nacos 命名空间,用于隔离不同环境的配置
|
||||
group: DEFAULT_GROUP # Nacos 分组,默认为 DEFAULT_GROUP
|
||||
file-extension: yml # Data ID 配置文件格式,默认为 properties
|
||||
# 如果配置了共享配置,这里可以不指定 Data ID,或者指定应用特有的配置
|
||||
# data-ids: ${spring.application.name}.${spring.cloud.nacos.config.file-extension}
|
||||
# auto-refresh: true # 是否自动刷新配置,默认为 true
|
||||
# bootstrap: true # 是否在 bootstrap 阶段加载配置,默认为 true
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848 # Nacos Server 地址
|
||||
namespace: trade_dev # Nacos 命名空间
|
||||
group: DEFAULT_GROUP # Nacos 分组
|
||||
|
||||
# 配置日志文件名称,确保在 Nacos 配置加载前,日志系统就能正确初始化
|
||||
logging:
|
||||
file:
|
||||
name: logs/${spring.application.name}.log
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
<logger name="com.trade.strategy" level="debug"/>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user