瀏覽代碼

上传 ibit-java exchange 源码

jean 4 小時之前
當前提交
387fe4c19a
共有 100 個文件被更改,包括 4802 次插入0 次删除
  1. 52 0
      copy/.gitignore
  2. 45 0
      copy/copy-trade-admin/.gitignore
  3. 102 0
      copy/copy-trade-admin/pom.xml
  4. 19 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/CopyTradeAdminApplication.java
  5. 22 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/bean/AliyunOssConfig.java
  6. 120 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/bean/RedisLock.java
  7. 77 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/HeaderLocaleResolver.java
  8. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/HttpSessionConfig.java
  9. 24 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/KafkaConfig.java
  10. 10 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/MyMetaObjectHandler.java
  11. 34 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/RedisConfig.java
  12. 53 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/SwaggerConfig.java
  13. 103 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/WebMvcConfigration.java
  14. 258 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/mybatis/BusinessPerformanceInterceptor.java
  15. 36 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/mybatis/MybatisPlusConfig.java
  16. 23 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/config/mybatis/PoMetaObjectHandler.java
  17. 46 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/constant/DogeApi.java
  18. 34 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/constant/KafkaMessageType.java
  19. 62 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/constant/KafkaTopic.java
  20. 262 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/consumer/KafkaConsumer.java
  21. 71 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/consumer/MarketListener.java
  22. 26 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/consumer/MessagePushConsumer.java
  23. 47 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/ClosePositionController.java
  24. 48 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/CopiedTradeController.java
  25. 112 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/CustomerController.java
  26. 34 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/CustomerFollowSymbolController.java
  27. 38 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/FavoriteController.java
  28. 66 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/FollowConfigController.java
  29. 89 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/FollowController.java
  30. 54 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/PositionController.java
  31. 34 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/RiskControlController.java
  32. 60 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/StatisticsDataController.java
  33. 80 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TagController.java
  34. 57 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderDataController.java
  35. 81 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderLevelController.java
  36. 41 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderSymbolController.java
  37. 37 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderTagController.java
  38. 25 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/ClosePositionMapper.java
  39. 28 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/CopiedTradeMapper.java
  40. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/CustomerFollowSymbolMapper.java
  41. 38 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/CustomerMapper.java
  42. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/FavoriteMapper.java
  43. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/FollowConfigMapper.java
  44. 31 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/FollowMapper.java
  45. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/KafkaMessageMapper.java
  46. 8 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/MessageMapper.java
  47. 65 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/PositionMapper.java
  48. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/RiskControlMapper.java
  49. 44 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/StatisticsDataMapper.java
  50. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/SymbolPriceMapper.java
  51. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TagMapper.java
  52. 27 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderDataMapper.java
  53. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderLevelMapper.java
  54. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderSymbolMapper.java
  55. 19 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderTagMapper.java
  56. 32 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/ClosePositionDeal.java
  57. 27 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/CloseType.java
  58. 177 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/ContractOrderEntrust.java
  59. 37 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/EntrustCallback.java
  60. 16 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/EntrustCancel.java
  61. 53 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/EntrustDeal.java
  62. 36 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/FollowClosePosition.java
  63. 76 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/FollowEntrust.java
  64. 24 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/Message.java
  65. 57 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/PositionDto.java
  66. 48 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/TraderClosePosition.java
  67. 100 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/TraderOrder.java
  68. 21 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/AgentStudentPositionForm.java
  69. 34 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/ClosePositionForm.java
  70. 23 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/CopiedTradeForm.java
  71. 22 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/FollowConfigForm.java
  72. 28 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/PositionForm.java
  73. 23 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/StatisticsDataForm.java
  74. 39 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/StudentPositionForm.java
  75. 22 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TagForm.java
  76. 15 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderDataQueryForm.java
  77. 29 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderForm.java
  78. 37 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderLevelForm.java
  79. 24 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderQueryForAdminForm.java
  80. 85 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/ClosePositionVo.java
  81. 59 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/CopiedTradeVo.java
  82. 87 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/CustomerVo.java
  83. 24 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/FolloweInforAgentVo.java
  84. 58 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/FollowerAgentVo.java
  85. 51 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/FollowerVo.java
  86. 20 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/PositionStatisticsVo.java
  87. 100 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/PositionVo.java
  88. 20 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/TagVo.java
  89. 76 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/TraderDataVo.java
  90. 46 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/filter/CrossDomainFilter.java
  91. 52 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/interceptor/AuthenticationInterceptor.java
  92. 49 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/IClosePositionService.java
  93. 64 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/ICopiedTradeService.java
  94. 24 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/ICustomerFollowSymbolService.java
  95. 50 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/ICustomerService.java
  96. 17 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/IFavoriteService.java
  97. 30 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/IFollowConfigService.java
  98. 55 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/IFollowService.java
  99. 18 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/IKafkaMessageService.java
  100. 15 0
      copy/copy-trade-admin/src/main/java/com/copy/trade/service/IMessageService.java

+ 52 - 0
copy/.gitignore

@@ -0,0 +1,52 @@
+# Eclipse files
+.classpath
+.project
+.settings/
+
+# Built application files
+*.apk
+*.ap_
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+/bin/
+/gen/
+/out/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# Intellij
+*.iml
+.idea/
+
+# Maven
+target/
+
+# Keystore files
+*.jks
+
+# Mac OS
+.DS_Store
+

+ 45 - 0
copy/copy-trade-admin/.gitignore

@@ -0,0 +1,45 @@
+#eclipse files
+.classpath
+.project
+
+# Built application files
+*.apk
+*.ap_
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+/bin/
+/gen/
+/out/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# Intellij
+*.iml
+
+# Keystore files
+*.jks
+
+/target/

+ 102 - 0
copy/copy-trade-admin/pom.xml

@@ -0,0 +1,102 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>com.copy.trade</groupId>
+		<artifactId>copy-trade</artifactId>
+		<version>1.0-SNAPSHOT</version>
+	</parent>
+	<groupId>com.copy.trade</groupId>
+	<artifactId>copy-trade-admin</artifactId>
+	<version>1.0.0-SNAPSHOT</version>
+	<name>copy-trade-admin</name>
+
+	<properties>
+		<aliyun.oss.verison>3.10.2</aliyun.oss.verison>
+	</properties>
+	<repositories>
+		<repository>
+			<id>jitpack.io</id>
+			<url>https://jitpack.io</url>
+		</repository>
+	</repositories>
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-redis</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.session</groupId>
+			<artifactId>spring-session-data-redis</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.kafka</groupId>
+			<artifactId>spring-kafka</artifactId>
+		</dependency>
+
+		<!--http-->
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+			<version>${http.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>fastjson</artifactId>
+			<version>${fastjson.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.aliyun.oss</groupId>
+			<artifactId>aliyun-sdk-oss</artifactId>
+			<version>${aliyun.oss.verison}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.amazonaws</groupId>
+			<artifactId>aws-java-sdk-s3</artifactId>
+			<version>1.12.527</version>
+		</dependency>
+
+		<!--jsonrpc依赖  -->
+	   <dependency>
+		    <groupId>com.github.briandilley.jsonrpc4j</groupId>
+		    <artifactId>jsonrpc4j</artifactId>
+		    <version>1.4.6</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.velocity</groupId>
+			<artifactId>velocity-engine-core</artifactId>
+			<version>2.0</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.tika</groupId>
+			<artifactId>tika-core</artifactId>
+			<version>1.18</version>
+		</dependency>
+		<dependency>
+			<groupId>com.copy.trade</groupId>
+			<artifactId>copy-trade-core</artifactId>
+			<version>1.0-SNAPSHOT</version>
+		</dependency>
+
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<version>${spring-boot.version}</version>
+				<configuration>
+					<executable>true</executable>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 19 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/CopyTradeAdminApplication.java

@@ -0,0 +1,19 @@
+package com.copy.trade;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@ComponentScan(basePackages = "com.copy.trade.*")
+@EnableCaching
+@EnableScheduling
+public class CopyTradeAdminApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(CopyTradeAdminApplication.class, args);
+	}
+
+}

+ 22 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/bean/AliyunOssConfig.java

@@ -0,0 +1,22 @@
+package com.copy.trade.bean;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+
+@Data
+@ConfigurationProperties(prefix = "aliyun.oss")
+@Component
+public class AliyunOssConfig {
+
+    private String endpoint;
+
+    private String accessKeyId;
+
+    private String accessKeySecret;
+
+    private String bucketPrivateName;
+
+    private String  bucketPublicName;
+}

+ 120 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/bean/RedisLock.java

@@ -0,0 +1,120 @@
+package com.copy.trade.bean;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.time.Duration;
+
+/**
+ * redis分布式锁工具类
+ */
+@Component
+@Slf4j
+public class RedisLock {
+
+    @Autowired
+    private StringRedisTemplate stringRedisTemplate;
+
+
+    /**
+     * 加锁
+     * @param key
+     * @param value
+     * @return
+     */
+    public boolean lock(String key,String value){
+
+        int loop = 5;
+        while (loop > 0){
+            if(stringRedisTemplate.opsForValue().setIfAbsent(key, value)){//对应setnx命令
+                //可以成功设置,也就是key不存在
+                return true;
+            }
+            if(stringRedisTemplate.opsForValue().get(key) == null){
+                stringRedisTemplate.delete(key);
+                //stringRedisTemplate.opsForValue().getOperations().delete(key);
+                if(stringRedisTemplate.opsForValue().setIfAbsent(key,value)){//对应setnx命令
+                    //可以成功设置,也就是key不存在
+                    return true;
+                }
+            }
+
+            //判断锁超时 - 防止原来的操作异常,没有运行解锁操作  防止死锁
+            String currentValue = stringRedisTemplate.opsForValue().get(key);
+            //如果锁过期
+            if(!StringUtils.isEmpty(currentValue)){
+                //获取上一个锁的value
+                String oldValue =stringRedisTemplate.opsForValue().getAndSet(key,value);//对应getset,如果key存在
+
+                //假设两个线程同时进来这里,因为key被占用了,而且锁过期了。获取的值currentValue=A(get取的旧的值肯定是一样的),两个线程的value都是B,key都是K.锁时间已经过期了。
+                //而这里面的getAndSet一次只会一个执行,也就是一个执行之后,上一个的value已经变成了B。只有一个线程获取的上一个值会是A,另一个线程拿到的值是B。
+                if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue) ){
+                    //oldValue不为空且oldValue等于currentValue,防止并发
+                    return true;
+                }
+            }
+            try {
+                Thread.sleep(200);
+            }catch (Exception e){
+                log.error("获取redis锁等待异常:",e);
+            }
+
+            loop--;
+        }
+        return false;
+    }
+
+    /**
+     * 加锁
+     * @param key
+     * @param value
+     * @Param time 过期时间(毫秒)
+     * @return
+     */
+    public boolean lock(String key,String value,long time){
+        int loop = 5;
+        while (loop > 0) {
+            if (stringRedisTemplate.opsForValue().setIfAbsent(key, value, Duration.ofMillis(time))) {//对应setnx命令
+                //可以成功设置,也就是key不存在
+                return true;
+            }
+            if (stringRedisTemplate.opsForValue().get(key) == null) {
+                stringRedisTemplate.delete(key);
+                //stringRedisTemplate.opsForValue().getOperations().delete(key);
+                if (stringRedisTemplate.opsForValue().setIfAbsent(key, value, Duration.ofMillis(time))) {//对应setnx命令
+                    //可以成功设置,也就是key不存在
+                    return true;
+                }
+            }
+            try {
+                Thread.sleep(100);
+            }catch (Exception e){
+                log.error("获取redis锁等待异常:",e);
+            }
+            loop--;
+        }
+        return false;
+    }
+
+
+    /**
+     * 解锁
+     * @param key
+     * @param value
+     */
+    public void unlock(String key,String value){
+        try {
+            String currentValue = stringRedisTemplate.opsForValue().get(key);
+            if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value) ){
+                 //stringRedisTemplate.opsForValue().getOperations().delete(key);//删除key
+                stringRedisTemplate.delete(key);
+            }
+        } catch (Exception e) {
+            log.error("[Redis分布式锁] 解锁出现异常了,{}",e);
+        }
+    }
+
+}

+ 77 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/HeaderLocaleResolver.java

@@ -0,0 +1,77 @@
+package com.copy.trade.config;
+
+import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.LocaleResolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Locale;
+
+/**
+ * 基于请求头的国际化语言解析器
+ * 优先级:请求头 lang > URL 参数 lang > Accept-Language 头 > 默认语言(英文)
+ * 解决移动端无法维持 Session 导致语言回落为中文的问题
+ *
+ * @author system
+ * @date 2026-05-15
+ */
+public class HeaderLocaleResolver implements LocaleResolver {
+
+    /** 默认语言,未携带语言参数时使用 */
+    private Locale defaultLocale = Locale.US;
+
+    /**
+     * 从请求中解析语言
+     *
+     * @param request HTTP 请求
+     * @return 解析到的 Locale
+     */
+    @Override
+    public Locale resolveLocale(HttpServletRequest request) {
+        // 1. 优先从请求头 lang 读取(移动端 App 方式)
+        String lang = request.getHeader("lang");
+
+        // 2. 请求头没有则尝试 URL 参数 lang(Web 方式)
+        if (!StringUtils.hasText(lang)) {
+            lang = request.getParameter("lang");
+        }
+
+        // 3. 解析语言标签
+        if (StringUtils.hasText(lang)) {
+            try {
+                // 兼容下划线格式(zh_CN)和连字符格式(zh-CN)
+                return StringUtils.parseLocale(lang);
+            } catch (Exception e) {
+                // 格式非法时继续走 Accept-Language
+            }
+        }
+
+        // 4. 尝试 Accept-Language 请求头
+        String acceptLanguage = request.getHeader("Accept-Language");
+        if (StringUtils.hasText(acceptLanguage)) {
+            try {
+                Locale locale = request.getLocale();
+                if (locale != null && StringUtils.hasText(locale.getLanguage())) {
+                    return locale;
+                }
+            } catch (Exception e) {
+                // 解析失败时使用默认语言
+            }
+        }
+
+        // 5. 使用默认语言
+        return defaultLocale;
+    }
+
+    /**
+     * 无状态解析器不支持主动设置语言
+     *
+     * @param request  HTTP 请求
+     * @param response HTTP 响应
+     * @param locale   目标 Locale(忽略)
+     */
+    @Override
+    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
+        // 无状态解析器不存储语言,忽略此操作
+    }
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/HttpSessionConfig.java

@@ -0,0 +1,16 @@
+package com.copy.trade.config;
+
+import com.copy.trade.constant.DogeApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
+import org.springframework.session.web.http.HeaderHttpSessionIdResolver;
+
+
+//@EnableRedisHttpSession
+public class HttpSessionConfig {
+
+    @Bean
+    public HeaderHttpSessionIdResolver httpSessionStrategy(){
+        return new HeaderHttpSessionIdResolver(DogeApi.SESSION_ADMIN);
+    }
+}

+ 24 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/KafkaConfig.java

@@ -0,0 +1,24 @@
+package com.copy.trade.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
+import org.springframework.kafka.core.ConsumerFactory;
+import org.springframework.kafka.listener.ContainerProperties;
+import org.springframework.kafka.listener.SeekToCurrentErrorHandler;
+import org.springframework.util.backoff.FixedBackOff;
+
+@Configuration
+public class KafkaConfig {
+
+    @Bean("ackContainerFactory")
+    public ConcurrentKafkaListenerContainerFactory ackContainerFactory(ConsumerFactory consumerFactory) {
+        ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory();
+        factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
+        factory.setConsumerFactory(consumerFactory);
+        // 重试10次,每次间隔2秒,超过后ack跳过
+        factory.setErrorHandler(new SeekToCurrentErrorHandler(new FixedBackOff(10000L, 10)));
+        return factory;
+    }
+
+}

+ 10 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/MyMetaObjectHandler.java

@@ -0,0 +1,10 @@
+package com.copy.trade.config;
+
+
+import com.copy.trade.config.mybatis.PoMetaObjectHandler;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MyMetaObjectHandler extends PoMetaObjectHandler {
+
+}

+ 34 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/RedisConfig.java

@@ -0,0 +1,34 @@
+package com.copy.trade.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.listener.ChannelTopic;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import com.copy.trade.consumer.MarketListener;
+
+
+@Configuration
+public class RedisConfig {
+
+	@Bean
+    public RedisMessageListenerContainer container(RedisConnectionFactory factory,MarketListener listener
+    ) {
+        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
+        container.setConnectionFactory(factory);
+        //订阅频道redis.news 和 redis.life  这个container 可以添加多个 messageListener
+        container.addMessageListener(listener, new ChannelTopic("market-contract"));
+        return container;
+    }
+	
+	 @Bean
+	 public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
+	      RedisTemplate<String,Object> redisTemplate = new RedisTemplate<String,Object>();
+	      redisTemplate.setConnectionFactory(redisConnectionFactory);
+	      return redisTemplate;
+	 }
+}

+ 53 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/SwaggerConfig.java

@@ -0,0 +1,53 @@
+package com.copy.trade.config;
+
+
+import com.copy.trade.constant.DogeApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.SessionAttribute;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        ParameterBuilder tokenPar = new ParameterBuilder();
+        List<Parameter> pars = new ArrayList<>();
+        tokenPar.name(DogeApi.TOKEN_NAME).description("认证令牌").modelRef(new ModelRef("string")).parameterType("header").required(true).build();
+        pars.add(tokenPar.build());
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                .apis(RequestHandlerSelectors.basePackage("com.copy.trade"))
+                .paths(PathSelectors.any())
+                .build()
+                .globalOperationParameters(pars)
+                .ignoredParameterTypes(SessionAttribute.class, HttpSession.class, HttpServletRequest.class, HttpServletResponse.class);
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("跟单后台接口")
+                .description("跟单后台接口")
+                .termsOfServiceUrl("")
+                .version("1.0")
+                .build();
+    }
+
+}

+ 103 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/WebMvcConfigration.java

@@ -0,0 +1,103 @@
+package com.copy.trade.config;
+
+import com.copy.trade.interceptor.AuthenticationInterceptor;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.filter.ShallowEtagHeaderFilter;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.Locale;
+
+@Configuration
+public class WebMvcConfigration  implements WebMvcConfigurer{
+
+    @Resource
+    private AuthenticationInterceptor authenticationInterceptor;
+
+    @Autowired
+    private LocaleChangeInterceptor localeChangeInterceptor;
+
+
+    String[] excludePathPatterns = {
+            //swagger
+            "/v2/api-docs",
+            "/swagger-resources",
+            "/swagger-resources/**",
+            "/configuration/ui",
+            "/configuration/security",
+            "/swagger-ui.html",
+            "/webjars/**",
+            "/api-docs**",
+            //不需要登陆
+            "/error"
+    };
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+
+        registry.addInterceptor(authenticationInterceptor)
+                .excludePathPatterns(excludePathPatterns)
+                .addPathPatterns("/**");
+        registry.addInterceptor(localeChangeInterceptor);
+    }
+
+    /**
+     * lang变更拦截器
+     *
+     * @return
+     */
+    @Bean
+    public LocaleChangeInterceptor localeChangeInterceptor() {
+        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
+        lci.setIgnoreInvalidLocale(true);
+        lci.setParamName("lang");
+        return lci;
+    }
+
+    /**
+     * 国际化语言解析器
+     * 从请求头 lang 或 URL 参数 lang 中读取语言,无需 Session,兼容移动端
+     *
+     * @return HeaderLocaleResolver
+     */
+    @Bean
+    public LocaleResolver localeResolver() {
+        return new HeaderLocaleResolver();
+    }
+
+
+    /**
+     * 响应添加etag,用于做get请求的304
+     *
+     * @return
+     */
+    @Bean
+    public ShallowEtagHeaderFilter shallowEtagHeaderFilter() {
+        return new ShallowEtagHeaderFilter();
+    }
+
+    @Bean
+    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
+        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
+        ObjectMapper objectMapper = converter.getObjectMapper();
+        //反序列化失败
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+        SimpleModule simpleModule = new SimpleModule();
+        //统一bigdecimal转为字符串
+        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
+        objectMapper.registerModule(simpleModule);
+        converter.setObjectMapper(objectMapper);
+        return converter;
+    }
+}

+ 258 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/mybatis/BusinessPerformanceInterceptor.java

@@ -0,0 +1,258 @@
+package com.copy.trade.config.mybatis;
+
+import com.baomidou.mybatisplus.core.toolkit.*;
+import com.baomidou.mybatisplus.core.toolkit.sql.SqlUtils;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.SystemMetaObject;
+import org.apache.ibatis.session.ResultHandler;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Statement;
+import java.util.*;
+
+/**
+ * <p>
+ * 性能分析拦截器,用于输出每条 SQL 语句及其执行时间
+ * </p>
+ *
+ * @author hubin nieqiurong TaoYu
+ * @since 2016-07-07
+ */
+@Intercepts({
+    @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
+    @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
+    @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
+})
+public class BusinessPerformanceInterceptor implements Interceptor {
+
+    private static final Log logger = LogFactory.getLog(BusinessPerformanceInterceptor.class);
+    private static final String DruidPooledPreparedStatement = "com.alibaba.druid.pool.DruidPooledPreparedStatement";
+    private static final String T4CPreparedStatement = "oracle.jdbc.driver.T4CPreparedStatement";
+    private static final String OraclePreparedStatementWrapper = "oracle.jdbc.driver.OraclePreparedStatementWrapper";
+    /**
+     * 打印预处理语句或打印带参数值的运行SQL语句
+     */
+    private boolean preparedStatement = true;                    //added by lijiabei
+    /**
+     * SQL 执行最大时长,超过自动停止运行,有助于发现问题。
+     */
+    private long maxTime = 0;
+    /**
+     * SQL 是否格式化
+     */
+    private boolean format = false;
+    /**
+     * 是否写入日志文件<br>
+     * true 写入日志文件,不阻断程序执行!<br>
+     * 超过设定的最大执行时长异常提示!
+     */
+    private boolean writeInLog = false;
+
+    public boolean isPreparedStatement() {
+		return preparedStatement;
+	}
+
+	public void setPreparedStatement(boolean preparedStatement) {
+		this.preparedStatement = preparedStatement;
+	}
+
+	public long getMaxTime() {
+		return maxTime;
+	}
+
+	public void setMaxTime(long maxTime) {
+		this.maxTime = maxTime;
+	}
+
+	public boolean isFormat() {
+		return format;
+	}
+
+	public void setFormat(boolean format) {
+		this.format = format;
+	}
+
+	public boolean isWriteInLog() {
+		return writeInLog;
+	}
+
+	public void setWriteInLog(boolean writeInLog) {
+		this.writeInLog = writeInLog;
+	}
+
+	private Method oracleGetOriginalSqlMethod;
+    private Method druidGetSQLMethod;
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        Statement statement;
+        Object firstArg = invocation.getArgs()[0];
+        if (Proxy.isProxyClass(firstArg.getClass())) {
+            statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement");
+        } else {
+            statement = (Statement) firstArg;
+        }
+        MetaObject stmtMetaObj = SystemMetaObject.forObject(statement);
+        try {
+            statement = (Statement) stmtMetaObj.getValue("stmt.statement");
+        } catch (Exception e) {
+            // do nothing
+        }
+        if (stmtMetaObj.hasGetter("delegate")) {
+            //Hikari
+            try {
+                statement = (Statement) stmtMetaObj.getValue("delegate");
+            } catch (Exception ignored) {
+
+            }
+        }
+
+        String originalSql = null;
+        String stmtClassName = statement.getClass().getName();
+        if (DruidPooledPreparedStatement.equals(stmtClassName)) {
+            try {
+                if (druidGetSQLMethod == null) {
+                    Class<?> clazz = Class.forName(DruidPooledPreparedStatement);
+                    druidGetSQLMethod = clazz.getMethod("getSql");
+                }
+                Object stmtSql = druidGetSQLMethod.invoke(statement);
+                if (stmtSql instanceof String) {
+                    originalSql = (String) stmtSql;
+                }
+                if(!preparedStatement){                                    //added by lijiabei
+                	originalSql = statement.toString();
+                }
+
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else if (T4CPreparedStatement.equals(stmtClassName)
+            || OraclePreparedStatementWrapper.equals(stmtClassName)) {
+            try {
+                if (oracleGetOriginalSqlMethod != null) {
+                    Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement);
+                    if (stmtSql instanceof String) {
+                        originalSql = (String) stmtSql;
+                    }
+                } else {
+                    Class<?> clazz = Class.forName(stmtClassName);
+                    oracleGetOriginalSqlMethod = getMethodRegular(clazz, "getOriginalSql");
+                    if (oracleGetOriginalSqlMethod != null) {
+                        //OraclePreparedStatementWrapper is not a public class, need set this.
+                        oracleGetOriginalSqlMethod.setAccessible(true);
+                        if (null != oracleGetOriginalSqlMethod) {
+                            Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement);
+                            if (stmtSql instanceof String) {
+                                originalSql = (String) stmtSql;
+                            }
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                //ignore
+            }
+        }
+        if (originalSql == null) {
+            originalSql = statement.toString();
+        }
+        originalSql = originalSql.replaceAll("[\\s]+", StringPool.SPACE);
+        int index = indexOfSqlStart(originalSql);
+        if (index > 0) {
+            originalSql = originalSql.substring(index);
+        }
+
+        // 计算执行 SQL 耗时
+        long start = SystemClock.now();
+        Object result = invocation.proceed();
+        long timing = SystemClock.now() - start;
+
+        // 格式化 SQL 打印执行结果
+        Object target = PluginUtils.realTarget(invocation.getTarget());
+        MetaObject metaObject = SystemMetaObject.forObject(target);
+        MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
+        StringBuilder formatSql = new StringBuilder()
+            .append(" Time:").append(timing)
+            .append(" ms - ID:").append(ms.getId())
+            .append(StringPool.NEWLINE).append("Execute SQL:")
+            .append(SqlUtils.sqlFormat(originalSql, format)).append(StringPool.NEWLINE);
+        if (this.writeInLog) {
+            if (this.maxTime >= 1 && timing > this.maxTime) {
+                logger.error(formatSql.toString());
+            } else {
+                logger.debug(formatSql.toString());
+            }
+        } else {
+            System.err.println(formatSql.toString());
+            Assert.isFalse(this.maxTime >= 1 && timing > this.maxTime,
+                " The SQL execution time is too large, please optimize ! ");
+        }
+        return result;
+    }
+
+    @Override
+    public Object plugin(Object target) {
+        if (target instanceof StatementHandler) {
+            return Plugin.wrap(target, this);
+        }
+        return target;
+    }
+
+    @Override
+    public void setProperties(Properties prop) {
+        String maxTime = prop.getProperty("maxTime");
+        String format = prop.getProperty("format");
+        if (StringUtils.isNotEmpty(maxTime)) {
+            this.maxTime = Long.parseLong(maxTime);
+        }
+        if (StringUtils.isNotEmpty(format)) {
+            this.format = Boolean.valueOf(format);
+        }
+    }
+
+    /**
+     * 获取此方法名的具体 Method
+     *
+     * @param clazz      class 对象
+     * @param methodName 方法名
+     * @return 方法
+     */
+    public Method getMethodRegular(Class<?> clazz, String methodName) {
+        if (Object.class.equals(clazz)) {
+            return null;
+        }
+        for (Method method : clazz.getDeclaredMethods()) {
+            if (method.getName().equals(methodName)) {
+                return method;
+            }
+        }
+        return getMethodRegular(clazz.getSuperclass(), methodName);
+    }
+
+    /**
+     * 获取sql语句开头部分
+     *
+     * @param sql
+     * @return
+     */
+    private int indexOfSqlStart(String sql) {
+        String upperCaseSql = sql.toUpperCase();
+        Set<Integer> set = new HashSet<>();
+        set.add(upperCaseSql.indexOf("SELECT "));
+        set.add(upperCaseSql.indexOf("UPDATE "));
+        set.add(upperCaseSql.indexOf("INSERT "));
+        set.add(upperCaseSql.indexOf("DELETE "));
+        set.remove(-1);
+        if (CollectionUtils.isEmpty(set)) {
+            return -1;
+        }
+        List<Integer> list = new ArrayList<>(set);
+        list.sort(Comparator.naturalOrder());
+        return list.get(0);
+    }
+}

+ 36 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/mybatis/MybatisPlusConfig.java

@@ -0,0 +1,36 @@
+package com.copy.trade.config.mybatis;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan({"com.copy.trade.dao*"})
+public class MybatisPlusConfig {
+
+    /**
+     * mybatis-plus SQL执行效率插件【生产环境可以关闭】
+     */
+    @Bean
+    @ConditionalOnProperty(prefix = "mybatis-plus.configuration",name = "log-performance",havingValue = "true",matchIfMissing = false)
+    public BusinessPerformanceInterceptor performanceInterceptor() {
+    	BusinessPerformanceInterceptor finPerformanceInterceptor = new BusinessPerformanceInterceptor();
+    	finPerformanceInterceptor.setPreparedStatement(false);
+        return finPerformanceInterceptor;
+    }
+
+    /**
+     * mybatis-plus分页插件<br>
+     * 文档:http://mp.baomidou.com<br>
+     */
+    @Bean
+    public PaginationInterceptor paginationInterceptor() {
+        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+        return paginationInterceptor;
+    }
+
+
+
+}

+ 23 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/config/mybatis/PoMetaObjectHandler.java

@@ -0,0 +1,23 @@
+package com.copy.trade.config.mybatis;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.reflection.MetaObject;
+
+import java.time.ZonedDateTime;
+import java.util.Date;
+
+@Slf4j
+public class PoMetaObjectHandler implements MetaObjectHandler {
+
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        this.setInsertFieldValByName("createdTime", Date.from(ZonedDateTime.now().toInstant()), metaObject);
+        this.updateFill(metaObject);
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        this.setUpdateFieldValByName("updatedTime", Date.from(ZonedDateTime.now().toInstant()), metaObject);
+    }
+}

+ 46 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/constant/DogeApi.java

@@ -0,0 +1,46 @@
+package com.copy.trade.constant;
+
+public interface DogeApi {
+
+    Integer SUCCESS = 0;
+
+    String TOKEN_NAME = "x-auth-token";
+
+    String SESSION_MEMBER = "API_MEMBER";
+    
+    String SESSION_ADMIN = "ADMIN_MEMBER";
+
+
+    //合约资产
+    String CONTRACT_ASSET = "/wallet-new/get";
+    
+    //所有资产
+    String ASSET_ALL = "/swap/asset/accounts";
+
+    //合约资产new(doge: /swap/wallet-new/contract-asset-new,GET ?memberId=)
+    String CONTRACT_ASSET_NEW = "/swap/wallet-new/contract-asset-new";
+
+    //跟单总转入转出
+    String FOLLOW_IN_OUT = "/swap/follow/tranfers";
+
+    //合约资产new学生
+    String CONTRACT_ASSET_NEW_STUDENT = "/swap/follow/wallets";
+
+    //当前持仓
+    String POSITION_LIST = "/position/list";
+
+    //当前委托
+    String CURRENT_ORDER = "/order/current";
+
+    //合约交易对
+    String SYMBOL = "/symbol";
+
+    //开户
+    String OPEN_ACCOUNT = "";
+
+    //合约委托下单
+    String ORDER_OPEN = "/order/open";
+
+    //获取当前价格
+    String CURRENT_SYMBOL_PRICE = "/symbol-price";
+}

+ 34 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/constant/KafkaMessageType.java

@@ -0,0 +1,34 @@
+package com.copy.trade.constant;
+
+public interface KafkaMessageType {
+
+    /**
+     * 合约委托
+     */
+    String CONTRACT_ENTRUST = "contract-entrust";
+
+    /**
+     * 合约委托撤单
+     */
+    String ENTRUST_CANCEL = "entrust-cancel";
+
+    /**
+     * 委托成交
+     */
+    String ENTRUST_DEAL = "entrust-deal";
+
+    /**
+     * 平仓委托
+     */
+    String CLOSE_POSITION = "close-position";
+
+    /**
+     * 平仓委托撤销
+     */
+    String CLOSE_POSITION_CANCEL = "close-position-cancel";
+
+    /**
+     * 平仓委托成交
+     */
+    String CLOSE_POSITION_DEAL = "close-position-deal";
+}

+ 62 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/constant/KafkaTopic.java

@@ -0,0 +1,62 @@
+package com.copy.trade.constant;
+
+public interface KafkaTopic {
+
+    /**
+     * 交易员委托消息
+     */
+    String COPY_TRADE = "copy-trade";
+
+    /**
+     * 跟单委托
+     */
+    String FOLLOW_ENTRUST = "follow-entrust";
+    
+    /**
+     * 超级交易员的跟单委托
+     */
+    String SPECIAL_FOLLOW_ENTRUST = "special-follow-entrust";
+
+    /**
+     * 跟单委托回调
+     */
+    String ENTRUST_CALLBACK = "entrust-callback";
+
+    /**
+     * 委托撤单
+     */
+    String FOLLOW_ENTRUST_CANCEL = "follow-entrust-cancel";
+
+
+    /**
+     * 跟单持仓
+     */
+    String FOLLOW_POSITION = "follow-position";
+
+
+    /**
+     * 跟单平仓消息
+     */
+    String FOLLOW_CLOSE_POSITION = "follow-close-position";
+
+    /**
+     * 跟单平仓委托回调
+     */
+    String CLOSE_POSITION_CALLBACK = "close-position-callback";
+
+    /**
+     * 撤销平仓委托
+     */
+    String CLOSE_POSITION_CANCEL = "close-position-cancel";
+    
+    /**
+     * 止盈止损强平消息
+     */
+    String FOLLOW_POSITION_FORCE_CLOSE = "swap-follow-position-force-close";
+    
+    //修改昵称或者头像同步信息
+    String SYNCHRONOUS_INFORMATION = "follow-account-info-change";
+
+
+
+}

+ 262 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/consumer/KafkaConsumer.java

@@ -0,0 +1,262 @@
+package com.copy.trade.consumer;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.copy.trade.constant.KafkaMessageType;
+import com.copy.trade.constant.KafkaTopic;
+import com.copy.trade.constant.RedisKey;
+import com.copy.trade.entity.dto.*;
+import com.copy.trade.service.IClosePositionService;
+import com.copy.trade.service.ICopiedTradeService;
+import com.copy.trade.service.IPositionService;
+import com.copy.trade.util.BeanCopior;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.support.Acknowledgment;
+import org.springframework.stereotype.Component;
+
+@Component
+public class KafkaConsumer {
+    private final Logger log = LoggerFactory.getLogger(KafkaConsumer.class);
+
+    private final ExecutorService entrustCallbackExecutor = Executors.newFixedThreadPool(8);
+
+    @Autowired
+    private ICopiedTradeService copiedTradeServiceImpl;
+
+    @Autowired
+    private IPositionService positionServiceImpl;
+
+    @Autowired
+    private IClosePositionService closePositionServiceImpl;
+
+    @Autowired
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Autowired
+    private KafkaTemplate<String, String> kafkaTemplate;
+
+    //开仓成功消息
+    @KafkaListener(topics = {"swap-order-open-done"}, containerFactory = "ackContainerFactory")
+    public void onSwapOrderOpen(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        try {
+            ContractOrderEntrust contractOrderEntrust = JSONObject.parseObject(record.value(), ContractOrderEntrust.class);
+            if (contractOrderEntrust.getFollowId() != null) {
+                final ContractOrderEntrust finalOrder = contractOrderEntrust;
+                entrustCallbackExecutor.submit(() -> {
+                    try {
+                        copiedTradeServiceImpl.entrustCallback(finalOrder);
+                    } catch (org.springframework.dao.DataIntegrityViolationException ex) {
+                        // 唯一索引冲突:说明另一线程已写入,忽略
+                        log.warn("entrustCallback 重复写入已忽略, followSystemId={}", finalOrder.getFollowSystemId());
+                    } catch (Exception ex) {
+                        log.error("entrustCallback 异步执行异常, memberId={}", finalOrder.getMemberId(), ex);
+                    }
+                });
+                ack.acknowledge();
+            } else {
+                Boolean entrust = copiedTradeServiceImpl.copyTrade(contractOrderEntrust);
+                if (entrust) {
+                    ack.acknowledge();
+                }
+            }
+        } catch (Exception e) {
+            log.error("开仓成功发生异常:", e);
+            log.info("order:" + record.value());
+            ack.acknowledge();
+        }
+    }
+
+    //平仓成功消息
+    @KafkaListener(topics = {"swap-order-close-done"}, containerFactory = "ackContainerFactory")
+    public void onSwapOrderClose(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        try {
+            ContractOrderEntrust contractOrderEntrust = JSONObject.parseObject(record.value(), ContractOrderEntrust.class);
+            Integer entrust = closePositionServiceImpl.traderClosePositionSuccess(contractOrderEntrust);
+            if (entrust==0) {
+                stringRedisTemplate.delete("CLOSE_RETRY_COUNT:" + contractOrderEntrust.getPositionId());
+                ack.acknowledge();
+            } else if (entrust==2) {
+                log.error("平仓处理,开仓数据丢失,重建开仓平仓组合记录, positionId:{}", contractOrderEntrust.getPositionId());
+                closePositionServiceImpl.reconstructOpenAndClose(contractOrderEntrust);
+                ack.acknowledge();
+            }
+            // 通知 doge 刷新交易账户与跟单账户内存缓存
+            kafkaTemplate.send("trading-account-change", contractOrderEntrust.getMemberId() + "");
+            kafkaTemplate.send("follow-account-change", contractOrderEntrust.getMemberId() + "");
+        } catch (Exception e) {
+            log.error("平仓成功发生异常, order:{}", record.value(), e);
+            ack.acknowledge();
+        }
+    }
+
+
+    //跟单开仓失败消息
+    @KafkaListener(topics = {"swap-follow-order-open-fail"}, containerFactory = "ackContainerFactory")
+    public void onSwapFollowOrderOpenFail(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        try {
+            ContractOrderEntrust contractOrderEntrust = JSONObject.parseObject(record.value(), ContractOrderEntrust.class);
+            if (contractOrderEntrust.getFollowId() != null) {
+                Boolean entrust = copiedTradeServiceImpl.entrustFollowOpenfail(contractOrderEntrust);
+                if (entrust) {
+                    ack.acknowledge();
+                }
+            }
+        } catch (Exception e) {
+            log.error("开仓失败发生异常:", e);
+            log.info("order:" + record.value());
+            ack.acknowledge();
+        }
+    }
+
+    //跟单平仓失败消息
+    @KafkaListener(topics = {"swap-follow-order-close-fail"}, containerFactory = "ackContainerFactory")
+    public void onSwapFollowOrderCloseFail(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        try {
+            ContractOrderEntrust contractOrderEntrust = JSONObject.parseObject(record.value(), ContractOrderEntrust.class);
+            if (contractOrderEntrust.getFollowId() != null) {
+                Boolean callback = closePositionServiceImpl.followClosePositionCallback(contractOrderEntrust);
+                if (callback) {
+                    ack.acknowledge();
+                }
+            }
+        } catch (Exception e) {
+            log.error("平仓失败发生异常:", e);
+            log.info("order:" + record.value());
+            ack.acknowledge();
+        }
+    }
+
+
+    /**
+     * 委托/撤单消费者
+     *
+     * @param record
+     * @param ack
+     */
+    @KafkaListener(topics = {KafkaTopic.COPY_TRADE}, containerFactory = "ackContainerFactory")
+    public void traderOrder(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        Boolean valid = valid(KafkaTopic.COPY_TRADE, record);
+        if (!valid) {
+            ack.acknowledge();
+            return;
+        }
+        Message msg = JSONObject.parseObject(record.value(), Message.class);
+        Boolean entrust = false;
+        //校验业务类型
+        switch (msg.getType()) {
+            case KafkaMessageType.CONTRACT_ENTRUST:
+                ContractOrderEntrust contractOrderEntrust = JSONObject.parseObject(msg.getValue(), ContractOrderEntrust.class);
+                entrust = copiedTradeServiceImpl.copyTrade(contractOrderEntrust);
+                break;
+            case KafkaMessageType.ENTRUST_CANCEL:
+                EntrustCancel entrustCancel = JSONObject.parseObject(msg.getValue(), EntrustCancel.class);
+                entrust = copiedTradeServiceImpl.entrustCancel(entrustCancel);
+                break;
+        }
+        if (entrust) {
+            ack.acknowledge();
+        }
+    }
+
+    /**
+     * 委托回调
+     *
+     * @param record
+     * @param ack
+     */
+    @KafkaListener(topics = {KafkaTopic.ENTRUST_CALLBACK}, containerFactory = "ackContainerFactory")
+    public void entrustCallback(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        Boolean valid = valid(KafkaTopic.ENTRUST_CALLBACK, record);
+        if (!valid) {
+            ack.acknowledge();
+            return;
+        }
+        //EntrustCallback entrustCallback = JSONObject.parseObject(record.value(), EntrustCallback.class);
+        //Boolean callback = copiedTradeServiceImpl.entrustCallback(entrustCallback);
+        //if(callback){
+        ack.acknowledge();
+        //}
+    }
+
+
+    /**
+     * 成交持仓
+     *
+     * @param record
+     * @param ack
+     */
+    @KafkaListener(topics = {KafkaTopic.FOLLOW_POSITION}, containerFactory = "ackContainerFactory")
+    public void entrustDeal(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        Boolean valid = valid(KafkaTopic.FOLLOW_POSITION, record);
+        if (!valid) {
+            ack.acknowledge();
+            return;
+        }
+        Message msg = JSONObject.parseObject(record.value(), Message.class);
+        Boolean deal = false;
+        switch (msg.getType()) {
+            case KafkaMessageType.ENTRUST_DEAL:
+                EntrustDeal entrustDeal = JSONObject.parseObject(msg.getValue(), EntrustDeal.class);
+                deal = positionServiceImpl.entrustDeal(entrustDeal);
+                break;
+            case KafkaMessageType.CLOSE_POSITION:
+                TraderClosePosition traderClosePosition = JSONObject.parseObject(msg.getValue(), TraderClosePosition.class);
+                deal = closePositionServiceImpl.traderClosePosition(traderClosePosition);
+                break;
+            case KafkaMessageType.CLOSE_POSITION_CANCEL:
+                String contractClosePositionEntrustNo = msg.getValue();
+                deal = closePositionServiceImpl.cancel(contractClosePositionEntrustNo);
+                break;
+            case KafkaMessageType.CLOSE_POSITION_DEAL:
+                ClosePositionDeal closePositionDeal = JSONObject.parseObject(msg.getValue(), ClosePositionDeal.class);
+                deal = closePositionServiceImpl.closePositionDeal(closePositionDeal);
+                break;
+        }
+
+        if (deal) {
+            ack.acknowledge();
+            return;
+        }
+    }
+
+
+    @KafkaListener(topics = {KafkaTopic.CLOSE_POSITION_CALLBACK}, containerFactory = "ackContainerFactory")
+    public void followClosePositionCallback(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        Boolean valid = valid(KafkaTopic.CLOSE_POSITION_CALLBACK, record);
+        if (!valid) {
+            ack.acknowledge();
+            return;
+        }
+        EntrustCallback entrustCallback = JSONObject.parseObject(record.value(), EntrustCallback.class);
+        /*
+         * Boolean callback =
+         * closePositionServiceImpl.followClosePositionCallback(entrustCallback);
+         * if(callback){ ack.acknowledge(); return ; }
+         */
+    }
+
+    private Boolean valid(String topic, ConsumerRecord<String, String> record) {
+        String messsage = record.value();
+        log.info("{}队列收到消息offset == {},key == {},value == {}", topic, record.offset(), record.key(), messsage);
+        if (!messsage.startsWith("{") || !messsage.endsWith("}")) {
+            return false;
+        }
+        return true;
+    }
+
+}

+ 71 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/consumer/MarketListener.java

@@ -0,0 +1,71 @@
+package com.copy.trade.consumer;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.connection.Message;
+import org.springframework.data.redis.connection.MessageListener;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class MarketListener implements MessageListener {
+	@Autowired
+	private RedisTemplate redisTemplate;
+
+	private static final String PRICE_CACHE_KEY = "copy:market:price";
+
+	private Map<String, BigDecimal> currentPriceMap = new HashMap<String, BigDecimal>();
+
+	/** 启动时从 Redis 预热价格,避免重启后短暂显示 -- */
+	@PostConstruct
+	public void init() {
+		try {
+			Map<Object, Object> cached = redisTemplate.opsForHash().entries(PRICE_CACHE_KEY);
+			if (cached != null && !cached.isEmpty()) {
+				cached.forEach((k, v) -> {
+					try {
+						currentPriceMap.put(k.toString(), new BigDecimal(v.toString()));
+					} catch (Exception ignored) {}
+				});
+				log.info("MarketListener preloaded {} prices from Redis", currentPriceMap.size());
+			}
+		} catch (Exception e) {
+			log.warn("MarketListener init preload failed: {}", e.getMessage());
+		}
+	}
+
+	@Override
+	public void onMessage(Message message, byte[] pattern) {
+		byte[] messageBody = message.getBody();
+        Object msg = redisTemplate.getValueSerializer().deserialize(messageBody);
+        JSONObject thumb = JSON.parseObject(msg.toString());
+        String symbol = thumb.getString("symbol");
+        BigDecimal close = thumb.getBigDecimal("close");
+        this.updatePrice(symbol, close);
+	}
+
+	public void updatePrice(String symbol, BigDecimal price) {
+		currentPriceMap.put(symbol, price);
+		// 同时持久化到 Redis,供重启时预热
+		try {
+			redisTemplate.opsForHash().put(PRICE_CACHE_KEY, symbol, price.toPlainString());
+		} catch (Exception ignored) {}
+	}
+
+	public Map<String, BigDecimal> getCurrentPriceMap() {
+		return currentPriceMap;
+	}
+
+}

+ 26 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/consumer/MessagePushConsumer.java

@@ -0,0 +1,26 @@
+package com.copy.trade.consumer;
+
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.kafka.support.Acknowledgment;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSON;
+import com.copy.trade.entity.po.Message;
+import com.copy.trade.service.IMessageService;
+
+@Component
+public class MessagePushConsumer {
+	
+	@Autowired
+	private IMessageService messageServiceImpl;
+
+	@KafkaListener(topics = {"follow-message-push"},containerFactory = "ackContainerFactory")
+    public void onMessagePush(ConsumerRecord<String, String> record, Acknowledgment ack){
+		Message message = JSON.parseObject(record.value(), Message.class);
+		messageServiceImpl.saveMessage(message);
+		
+		ack.acknowledge();
+	}
+}

+ 47 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/ClosePositionController.java

@@ -0,0 +1,47 @@
+package com.copy.trade.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.form.ClosePositionForm;
+import com.copy.trade.entity.vo.ClosePositionVo;
+import com.copy.trade.service.IClosePositionService;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+/**
+ * <p>
+ * 平仓记录 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-22
+ */
+@Api(value = "平仓记录", tags = "平仓记录")
+@RestController
+@RequestMapping("/close-position")
+public class ClosePositionController {
+
+	IClosePositionService closePositionServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param closePositionServiceImpl
+	 */	
+	@Autowired
+	ClosePositionController(IClosePositionService closePositionServiceImpl) {
+		this.closePositionServiceImpl = closePositionServiceImpl;
+	}
+	
+
+	@ApiOperation(value = "平仓记录列表")
+	@PostMapping("/list")
+	public Page<ClosePositionVo> list(@RequestBody ClosePositionForm closePositionForm){
+		return closePositionServiceImpl.list(closePositionForm);
+	}
+
+}

+ 48 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/CopiedTradeController.java

@@ -0,0 +1,48 @@
+package com.copy.trade.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.base.BaseQueryForm;
+import com.copy.trade.entity.form.CopiedTradeForm;
+import com.copy.trade.entity.po.CopiedTrade;
+import com.copy.trade.entity.vo.CopiedTradeVo;
+import com.copy.trade.service.ICopiedTradeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+/**
+ * <p>
+ * 跟单记录表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+@Api(value = "跟单记录表", tags = "跟单记录")
+@RestController
+@RequestMapping("/copied-trade")
+public class CopiedTradeController {
+
+	ICopiedTradeService copiedTradeServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param copiedTradeServiceImpl
+	 */	
+	@Autowired
+	CopiedTradeController(ICopiedTradeService copiedTradeServiceImpl) {
+		this.copiedTradeServiceImpl = copiedTradeServiceImpl;
+	}
+
+	
+	@ApiOperation(value = "跟单列表")
+	@PostMapping("/list")
+	public Page<CopiedTradeVo> list(@RequestBody CopiedTradeForm copiedTradeForm){
+		return copiedTradeServiceImpl.list(copiedTradeForm);
+	}
+
+}

+ 112 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/CustomerController.java

@@ -0,0 +1,112 @@
+package com.copy.trade.controller;
+
+
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.base.BaseQueryForm;
+import com.copy.trade.entity.form.TraderForm;
+import com.copy.trade.entity.form.TraderQueryForAdminForm;
+import com.copy.trade.entity.po.Customer;
+import com.copy.trade.entity.vo.CustomerVo;
+import com.copy.trade.entity.vo.TraderTotalVo;
+import com.copy.trade.service.ICustomerService;
+import com.copy.trade.util.WebAssert;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 用户表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+@Api(value = "用户接口", tags = "关于用户的接口")
+@RestController
+@RequestMapping("/customer")
+public class CustomerController {
+
+	private final Logger log = LoggerFactory.getLogger(CustomerController.class);
+
+	ICustomerService customerServiceImpl;
+
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param customerServiceImpl
+	 */
+	@Autowired
+	CustomerController(ICustomerService customerServiceImpl) {
+		this.customerServiceImpl = customerServiceImpl;
+	}
+	
+	@ApiOperation(value = "交易员列表")
+	@PostMapping("/trader-list")
+	public Page<CustomerVo> traderList(@RequestBody TraderQueryForAdminForm traderQueryForAdminForm){
+		return customerServiceImpl.traderList(traderQueryForAdminForm);
+	}
+	
+	@ApiOperation(value = "交易员汇总列表")
+	@PostMapping("/trader-total-list")
+	public Page<TraderTotalVo> traderTotalList(@RequestBody TraderQueryForAdminForm traderQueryForAdminForm){
+		return customerServiceImpl.traderTotalList(traderQueryForAdminForm);
+	}
+	
+	@ApiOperation(value = "取消交易员")
+	@PutMapping("/cancel-trader/{traderId}")
+	public Boolean approvalTrader(@PathVariable Long traderId){
+		return customerServiceImpl.cancelTrader(traderId);
+
+	}
+	
+	@ApiOperation(value = "修改交易员等级")
+	@PutMapping("/update-trader-level/{traderId}/{levelId}")
+	public Boolean updateTraderLevel(@PathVariable Long traderId, @PathVariable Long levelId){
+		return customerServiceImpl.updateTraderLevelId(traderId, levelId);
+
+	}
+
+	@ApiOperation(value = "设置顶级交易员(1是 2否)")
+	@PutMapping("/update-trader-top/{traderId}/{isTop}")
+	public Boolean updateTraderTop(@PathVariable Long traderId, @PathVariable Integer isTop){
+		return customerServiceImpl.updateTraderTop(traderId, isTop);
+	}
+	
+	@ApiOperation(value = "修改交易员的配置参数")
+	@PutMapping("/update-trader-params/{traderId}")
+	public Boolean updateTraderParams(@PathVariable Long traderId,@RequestBody TraderForm traderForm){
+		return customerServiceImpl.updateTraderParams(traderId, traderForm);
+		
+	}
+	
+	@ApiOperation(value = "交易员申请列表")
+	@PostMapping("/applying-list")
+	public Page<Customer> applyingList(@RequestBody BaseQueryForm baseQueryForm){
+		return customerServiceImpl.applyList(baseQueryForm.newFormPage());
+	}
+
+	@ApiOperation(value = "批准交易员申请")
+	@PutMapping("/approval-trader/{traderId}/{levelId}")
+	public Boolean approvalTrader(@PathVariable Long traderId, @PathVariable Long levelId){
+		return customerServiceImpl.approvalTrader(traderId,levelId);
+
+	}
+
+	@ApiOperation(value = "拒绝交易员申请")
+	@PutMapping("/reject-trader/{traderId}")
+	public Boolean rejectTrader(@PathVariable Long traderId){
+		return customerServiceImpl.reject(traderId);
+	}
+	
+	@ApiOperation(value = "同步交易员昵称和头像")
+	@PostMapping("/synchronous-infor")
+	public Boolean synchronousTraderInfor(){
+		return customerServiceImpl.synchronousTraderInfor();
+	}
+
+}

+ 34 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/CustomerFollowSymbolController.java

@@ -0,0 +1,34 @@
+package com.copy.trade.controller;
+
+import com.copy.trade.service.ICustomerFollowSymbolService;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+/**
+ * <p>
+ * 用户跟随交易对 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+@Api(value = "用户跟随交易对", tags = "用户跟随交易对")
+@RestController
+@RequestMapping("/customer-follow-symbol")
+public class CustomerFollowSymbolController {
+
+	ICustomerFollowSymbolService customerFollowSymbolServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param customerFollowSymbolServiceImpl
+	 */	
+	@Autowired
+	CustomerFollowSymbolController(ICustomerFollowSymbolService customerFollowSymbolServiceImpl) {
+		this.customerFollowSymbolServiceImpl = customerFollowSymbolServiceImpl;
+	}
+	
+
+
+}

+ 38 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/FavoriteController.java

@@ -0,0 +1,38 @@
+package com.copy.trade.controller;
+
+
+import com.copy.trade.service.ICustomerService;
+import com.copy.trade.service.IFavoriteService;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 关注表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+@Api(value = "关注表", tags = "关注表")
+@RestController
+@RequestMapping("/favorite")
+public class FavoriteController {
+
+	IFavoriteService favoriteServiceImpl;
+
+	@Autowired
+	private ICustomerService customerServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param favoriteServiceImpl
+	 */	
+	@Autowired
+	FavoriteController(IFavoriteService favoriteServiceImpl) {
+		this.favoriteServiceImpl = favoriteServiceImpl;
+	}
+
+
+}

+ 66 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/FollowConfigController.java

@@ -0,0 +1,66 @@
+package com.copy.trade.controller;
+
+import com.alibaba.druid.util.StringUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.base.BaseQueryForm;
+import com.copy.trade.entity.form.FollowConfigForm;
+import com.copy.trade.entity.form.TraderForm;
+import com.copy.trade.entity.po.Customer;
+import com.copy.trade.entity.po.FollowConfig;
+import com.copy.trade.entity.po.Tag;
+import com.copy.trade.entity.vo.TagVo;
+import com.copy.trade.enums.FollowConfigEnum;
+import com.copy.trade.service.IFollowConfigService;
+import com.copy.trade.service.ITagService;
+import com.copy.trade.util.BeanCopior;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * <p>
+ * 配置表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+@Api(value = "跟单配置接口", tags = "跟单配置接口")
+@RestController
+@RequestMapping("/tag")
+public class FollowConfigController {
+
+	IFollowConfigService followConfigServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * 
+	 * @param followConfigServiceImpl
+	 */
+	@Autowired
+	FollowConfigController(IFollowConfigService followConfigServiceImpl) {
+		this.followConfigServiceImpl = followConfigServiceImpl;
+	}
+
+	@ApiOperation(value = "配置列表")
+	@PostMapping("/list")
+	public List<FollowConfig> list() {
+		//return followConfigServiceImpl.list();
+		return followConfigServiceImpl.getListForAdmin();
+	}
+	
+	@ApiOperation(value = "修改")
+	@PostMapping("/edit/")
+	public Boolean edit(@RequestBody FollowConfigForm followConfigForm) {
+		return followConfigServiceImpl.editById(followConfigForm);
+	}
+}

+ 89 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/FollowController.java

@@ -0,0 +1,89 @@
+package com.copy.trade.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.constant.DogeApi;
+import com.copy.trade.entity.base.BaseQueryForm;
+import com.copy.trade.entity.form.AgentStudentPositionForm;
+import com.copy.trade.entity.form.StudentPositionForm;
+import com.copy.trade.entity.po.Customer;
+import com.copy.trade.entity.po.Follow;
+import com.copy.trade.entity.vo.FolloweInforAgentVo;
+import com.copy.trade.entity.vo.FollowerAgentVo;
+import com.copy.trade.entity.vo.FollowerVo;
+import com.copy.trade.enums.FollowStatusEnum;
+import com.copy.trade.enums.TraderEnum;
+import com.copy.trade.service.ICustomerService;
+import com.copy.trade.service.IFollowService;
+import com.copy.trade.util.WebAssert;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+
+/**
+ * <p>
+ * 跟随表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+@Api(value = "跟随表", tags = "跟随表")
+@RestController
+@RequestMapping("/follow")
+public class FollowController {
+
+	IFollowService followServiceImpl;
+
+	@Autowired
+	private ICustomerService customerServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param followServiceImpl
+	 */	
+	@Autowired
+	FollowController(IFollowService followServiceImpl) {
+		this.followServiceImpl = followServiceImpl;
+	}
+	
+
+	public List<Follow> getByCustomerId(Long customerId) {
+		return followServiceImpl.getByCustomerId(customerId);
+	}
+	
+	@ApiOperation(value = "我的学生列表")
+	@PostMapping("/followers")
+	public Page<FollowerVo> followers(@RequestBody StudentPositionForm studentPositionForm){
+		Customer customer = customerServiceImpl.getByMemberId(studentPositionForm.getTraderMemberId());
+		WebAssert.isTrue(customer.getTrader() == TraderEnum.TRADER.getStatus(),"chk.not.trader");
+		studentPositionForm.setTraderId(customer.getId());
+		return followServiceImpl.followers(studentPositionForm);
+	}
+	
+	@ApiOperation(value = "代理商的学生列表")
+	@PostMapping("/followers-agent")
+	public Page<FollowerAgentVo> followersAgent(@RequestBody AgentStudentPositionForm agentStudentPositionForm){
+		return followServiceImpl.followersAgent(agentStudentPositionForm);
+	}
+	
+	@ApiOperation(value = "查询代理商下级的跟单信息")
+	@PostMapping("/follow-infor-agent")
+	public FolloweInforAgentVo selectFollowInforAgent(String subIds){
+		return followServiceImpl.selectFollowInforAgent(subIds);
+	}
+	
+	@ApiOperation(value = "移除跟随")
+	@PutMapping("/remove-follow")
+	public Boolean removeFollow(@RequestParam Long customerId,@RequestParam Long traderId){
+		return followServiceImpl.removeFollow(customerId,traderId);
+	}
+	
+}

+ 54 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/PositionController.java

@@ -0,0 +1,54 @@
+package com.copy.trade.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.form.CopiedTradeForm;
+import com.copy.trade.entity.form.PositionForm;
+import com.copy.trade.entity.vo.CopiedTradeVo;
+import com.copy.trade.entity.vo.PositionStatisticsVo;
+import com.copy.trade.entity.vo.PositionVo;
+import com.copy.trade.service.IPositionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+/**
+ * <p>
+ * 跟单持仓表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-17
+ */
+@Api(value = "跟单持仓表", tags = "跟单持仓表")
+@RestController
+@RequestMapping("/position")
+public class PositionController {
+
+	IPositionService positionServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param positionServiceImpl
+	 */	
+	@Autowired
+	PositionController(IPositionService positionServiceImpl) {
+		this.positionServiceImpl = positionServiceImpl;
+	}
+	
+	@ApiOperation(value = "跟单仓位列表")
+	@PostMapping("/list")
+	public Page<PositionVo> list(@RequestBody PositionForm positionForm){
+		return positionServiceImpl.list(positionForm);
+	}
+	
+	@ApiOperation(value = "仓位统计数据")
+	@PostMapping("/position-statistics")
+	public PositionStatisticsVo positionStatistics(){
+		return positionServiceImpl.getPositionStatistics();
+	}
+
+}

+ 34 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/RiskControlController.java

@@ -0,0 +1,34 @@
+package com.copy.trade.controller;
+
+import com.copy.trade.service.IRiskControlService;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+/**
+ * <p>
+ * 跟单风险控制表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+@Api(value = "跟单风险控制表", tags = "跟单风险控制表")
+@RestController
+@RequestMapping("/risk-control")
+public class RiskControlController {
+
+	IRiskControlService riskControlServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param riskControlServiceImpl
+	 */	
+	@Autowired
+	RiskControlController(IRiskControlService riskControlServiceImpl) {
+		this.riskControlServiceImpl = riskControlServiceImpl;
+	}
+	
+
+
+}

+ 60 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/StatisticsDataController.java

@@ -0,0 +1,60 @@
+package com.copy.trade.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.form.StatisticsDataForm;
+import com.copy.trade.entity.form.TraderDataQueryForm;
+import com.copy.trade.entity.po.StatisticsData;
+import com.copy.trade.entity.po.TraderData;
+import com.copy.trade.enums.TraderEnum;
+import com.copy.trade.service.IStatisticsDataService;
+import com.copy.trade.util.WebAssert;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+/**
+ * <p>
+ * 统计数据表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-29
+ */
+@Api(value = "每日统计数据表", tags = "每日统计数据表")
+@RestController
+@RequestMapping("/statistics-data")
+public class StatisticsDataController {
+
+	IStatisticsDataService statisticsDataServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param statisticsDataServiceImpl
+	 */	
+	@Autowired
+	StatisticsDataController(IStatisticsDataService statisticsDataServiceImpl) {
+		this.statisticsDataServiceImpl = statisticsDataServiceImpl;
+	}
+	
+	@ApiOperation(value = "每日统计数据列表")
+	@PostMapping("/list/{traderId}")
+	public List<StatisticsData> list(@PathVariable Long traderId){
+		WebAssert.isNotNull(traderId,"chk.trader.traderId.not.null");
+		return statisticsDataServiceImpl.traderDataList(traderId);
+	}
+	
+	@ApiOperation(value = "修改交易员每日统计数据")
+	@PostMapping("/edit")
+	public Boolean edit(@RequestBody List<StatisticsDataForm> statisticsDataForms){
+		return statisticsDataServiceImpl.edit(statisticsDataForms);
+	}
+
+}

+ 80 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TagController.java

@@ -0,0 +1,80 @@
+package com.copy.trade.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.copy.trade.entity.form.TagForm;
+import com.copy.trade.entity.po.Tag;
+import com.copy.trade.entity.vo.TagVo;
+import com.copy.trade.service.ITagService;
+import com.copy.trade.util.BeanCopior;
+import com.copy.trade.util.WebAssert;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * <p>
+ * 标签表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+@Api(value = "标签接口", tags = "标签接口")
+@RestController
+@RequestMapping("/tag")
+public class TagController {
+
+	ITagService tagServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param tagServiceImpl
+	 */	
+	@Autowired
+	TagController(ITagService tagServiceImpl) {
+		this.tagServiceImpl = tagServiceImpl;
+	}
+
+	@ApiOperation(value = "标签列表")
+	@GetMapping("/")
+	public List<TagVo> list(){
+		List<Tag> list = tagServiceImpl.list();
+		List<TagVo> tagVoList = BeanCopior.mapList(list, TagVo.class);
+		return tagVoList;
+	}
+
+	@ApiOperation(value="添加标签")
+	@ApiImplicitParam(name="tagForm",value = "标签表单",dataType = "TagForm")
+	@PostMapping("/add")
+	public Boolean add(@RequestBody @Valid TagForm tagForm){
+		QueryWrapper<Tag> tagQueryWrapper = new QueryWrapper<>();
+		tagQueryWrapper.eq("name",tagForm.getName());
+		Tag tag = tagServiceImpl.getOne(tagQueryWrapper);
+		WebAssert.isNull(tag,"标签已存在");
+		tag = new Tag();
+		tag.setName(tagForm.getName());
+		tag.setEnName(tagForm.getEnName());
+		return tagServiceImpl.save(tag);
+	}
+	
+	@ApiOperation(value="修改标签")
+	@ApiImplicitParam(name="tagForm",value = "标签表单",dataType = "TagForm")
+	@PostMapping("/update")
+	public Boolean update(@RequestBody @Valid TagForm tagForm){
+		Tag tag = tagServiceImpl.getById(tagForm.getId());
+		tag.setName(tagForm.getName());
+		tag.setEnName(tagForm.getEnName());
+		return tagServiceImpl.updateById(tag);
+	}
+	
+	@ApiOperation(value="删除标签")
+	@PutMapping("/delete/{id}")
+	public Boolean delete(@PathVariable Long id){
+		return tagServiceImpl.removeById(id);
+	}
+}

+ 57 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderDataController.java

@@ -0,0 +1,57 @@
+package com.copy.trade.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.form.CopiedTradeForm;
+import com.copy.trade.entity.form.TraderDataQueryForm;
+import com.copy.trade.entity.po.TraderData;
+import com.copy.trade.entity.vo.CopiedTradeVo;
+import com.copy.trade.entity.vo.TraderDataVo;
+import com.copy.trade.service.IPositionService;
+import com.copy.trade.service.ITraderDataService;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+/**
+ * <p>
+ * 交易员统计数据表  前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-17
+ */
+@Api(value = "交易员统计数据表", tags = "交易员统计数据表")
+@RestController
+@RequestMapping("/traderdata")
+public class TraderDataController {
+
+	ITraderDataService traderDataServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param traderDataServiceImpl
+	 */	
+	@Autowired
+	TraderDataController(ITraderDataService traderDataServiceImpl) {
+		this.traderDataServiceImpl = traderDataServiceImpl;
+	}
+	
+	@ApiOperation(value = "可以修改的交易员统计数据列表")
+	@PostMapping("/list")
+	public Page<TraderDataVo> list(@RequestBody TraderDataQueryForm traderQueryForAdminForm){
+		return traderDataServiceImpl.traderDataList(traderQueryForAdminForm);
+	}
+	
+	@ApiOperation(value = "修改交易员统计数据")
+	@PostMapping("/edit")
+	public Boolean edit(@RequestBody TraderData traderData){
+		return traderDataServiceImpl.edit(traderData);
+	}
+	
+
+}

+ 81 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderLevelController.java

@@ -0,0 +1,81 @@
+package com.copy.trade.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.copy.trade.entity.form.TraderLevelForm;
+import com.copy.trade.entity.po.TraderLevel;
+import com.copy.trade.service.ITraderLevelService;
+import com.copy.trade.util.BeanCopior;
+import com.copy.trade.util.WebAssert;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import javax.validation.Valid;
+
+/**
+ * <p>
+ * 交易员等级表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+@Api(value = "交易员等级表", tags = "交易员等级表")
+@RestController
+@RequestMapping("/trader-level")
+public class TraderLevelController {
+
+	ITraderLevelService traderLevelServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param traderLevelServiceImpl
+	 */	
+	@Autowired
+	TraderLevelController(ITraderLevelService traderLevelServiceImpl) {
+		this.traderLevelServiceImpl = traderLevelServiceImpl;
+	}
+	
+	@ApiOperation(value = "交易员等级列表")
+	@GetMapping("/")
+	public List<TraderLevel> list(){
+		return traderLevelServiceImpl.list();
+	}
+
+	@ApiOperation(value = "添加交易员等级")
+	@ApiImplicitParam(name = "traderLevelForm", value = "添加交易等级表单",dataType = "TraderLevelForm")
+	@PostMapping("/add")
+	public Boolean add(@RequestBody @Valid TraderLevelForm traderLevelForm){
+		QueryWrapper<TraderLevel> traderLevelQueryWrapper = new QueryWrapper<>();
+		traderLevelQueryWrapper.eq("name",traderLevelForm.getName());
+		TraderLevel traderLevel = traderLevelServiceImpl.getOne(traderLevelQueryWrapper);
+		WebAssert.isNull(traderLevel,"等级已存在");
+		traderLevel = BeanCopior.map(traderLevelForm, TraderLevel.class);
+		return traderLevelServiceImpl.save(traderLevel);
+	}
+	
+	@ApiOperation(value = "修改交易员等级")
+	@ApiImplicitParam(name = "traderLevelForm", value = "修改交易等级表单",dataType = "TraderLevelForm")
+	@PostMapping("/update")
+	public Boolean update(@RequestBody @Valid TraderLevelForm traderLevelForm){
+		TraderLevel traderLevel = BeanCopior.map(traderLevelForm, TraderLevel.class);
+		return traderLevelServiceImpl.updateById(traderLevel);
+	}
+	
+	@ApiOperation(value = "删除交易员等级")
+	@PutMapping("/delete/{id}")
+	public Boolean delete(@PathVariable Long id){
+		return traderLevelServiceImpl.removeById(id);
+	}
+
+}

+ 41 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderSymbolController.java

@@ -0,0 +1,41 @@
+package com.copy.trade.controller;
+
+import com.copy.trade.service.ICustomerService;
+import com.copy.trade.service.ITraderSymbolService;
+
+import io.swagger.annotations.Api;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+
+/**
+ * <p>
+ * 交易员带单合约 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+@Api(value = "交易员带单合约", tags = "交易员带单合约")
+@RestController
+@RequestMapping("/trader-symbol")
+public class TraderSymbolController {
+
+	ITraderSymbolService traderSymbolServiceImpl;
+
+	@Autowired
+	private ICustomerService customerServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param traderSymbolServiceImpl
+	 */	
+	@Autowired
+	TraderSymbolController(ITraderSymbolService traderSymbolServiceImpl) {
+		this.traderSymbolServiceImpl = traderSymbolServiceImpl;
+	}
+
+
+
+}

+ 37 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/controller/TraderTagController.java

@@ -0,0 +1,37 @@
+package com.copy.trade.controller;
+
+
+import com.copy.trade.service.ITraderTagService;
+
+import io.swagger.annotations.Api;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+
+/**
+ * <p>
+ * 交易员标签表 前端控制器
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+@Api(value = "交易员标签表", tags = "交易员标签表")
+@RestController
+@RequestMapping("/trader-tag")
+public class TraderTagController {
+
+	ITraderTagService traderTagServiceImpl;
+
+	/**
+	 * 推荐使用构造器注入
+	 * @param traderTagServiceImpl
+	 */	
+	@Autowired
+	TraderTagController(ITraderTagService traderTagServiceImpl) {
+		this.traderTagServiceImpl = traderTagServiceImpl;
+	}
+
+
+}

+ 25 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/ClosePositionMapper.java

@@ -0,0 +1,25 @@
+package com.copy.trade.dao;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.copy.trade.entity.form.ClosePositionForm;
+import com.copy.trade.entity.po.ClosePosition;
+import com.copy.trade.entity.vo.ClosePositionVo;
+
+/**
+ * <p>
+ * 平仓记录 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-22
+ */
+public interface ClosePositionMapper extends BaseMapper<ClosePosition> {
+
+	List<ClosePositionVo> page(@Param("page") Page page, @Param("closePositionForm") ClosePositionForm closePositionForm);
+
+}

+ 28 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/CopiedTradeMapper.java

@@ -0,0 +1,28 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.form.CopiedTradeForm;
+import com.copy.trade.entity.po.CopiedTrade;
+import com.copy.trade.entity.vo.CopiedTradeVo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * <p>
+ * 跟单记录表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface CopiedTradeMapper extends BaseMapper<CopiedTrade> {
+
+    BigDecimal sumPrincipalAmount(@Param("customerId") Long customerId, @Param("traderId") Long traderId);
+
+    List<CopiedTradeVo> page(@Param("page") Page page, @Param("copiedTradeForm") CopiedTradeForm copiedTradeForm);
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/CustomerFollowSymbolMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.CustomerFollowSymbol;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 用户跟随交易对 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface CustomerFollowSymbolMapper extends BaseMapper<CustomerFollowSymbol> {
+
+}

+ 38 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/CustomerMapper.java

@@ -0,0 +1,38 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.form.TraderQueryForAdminForm;
+import com.copy.trade.entity.po.Customer;
+import com.copy.trade.entity.vo.CustomerVo;
+import com.copy.trade.entity.vo.TraderTotalVo;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+ * <p>
+ * 用户表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface CustomerMapper extends BaseMapper<Customer> {
+
+	List<Customer> listByTraderStatus(@Param("page") Page page, @Param("status") Integer status);
+	
+	List<CustomerVo> traderList(@Param("page") Page page, @Param("traderQueryForm") TraderQueryForAdminForm traderQueryForm);
+	
+	List<TraderTotalVo> traderTotalList(@Param("page") Page page, @Param("traderQueryForm") TraderQueryForAdminForm traderQueryForm);
+	
+	Boolean cancelTrader(@Param("traderId") Long traderId);
+	
+	Boolean updateTraderLevelId(@Param("traderId") Long traderId, @Param("traderLevelId") Long traderLevelId);
+
+	Boolean updateTraderTop(@Param("traderId") Long traderId, @Param("isTop") Integer isTop);
+
+	Boolean clearMaxPrincipalAmount(@Param("traderId") Long traderId);
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/FavoriteMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.Favorite;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 关注表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface FavoriteMapper extends BaseMapper<Favorite> {
+
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/FollowConfigMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.copy.trade.entity.po.FollowConfig;
+
+/**
+ * <p>
+ * 标签表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+public interface FollowConfigMapper extends BaseMapper<FollowConfig> {
+
+}

+ 31 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/FollowMapper.java

@@ -0,0 +1,31 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.form.AgentStudentPositionForm;
+import com.copy.trade.entity.form.StudentPositionForm;
+import com.copy.trade.entity.po.Follow;
+import com.copy.trade.entity.vo.FollowerAgentVo;
+import com.copy.trade.entity.vo.FollowerVo;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+ * <p>
+ * 跟随表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface FollowMapper extends BaseMapper<Follow> {
+
+	List<Long> followering(Long traderId);
+	
+	List<FollowerVo> followers(@Param("page") Page page, @Param("studentPositionForm") StudentPositionForm studentPositionForm);
+	
+	List<FollowerAgentVo> followersAgent(@Param("page") Page page, @Param("agentStudentPositionForm") AgentStudentPositionForm agentStudentPositionForm);
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/KafkaMessageMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.KafkaMessage;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * kafka消息发送 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-22
+ */
+public interface KafkaMessageMapper extends BaseMapper<KafkaMessage> {
+
+}

+ 8 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/MessageMapper.java

@@ -0,0 +1,8 @@
+package com.copy.trade.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.copy.trade.entity.po.Message;
+
+public interface MessageMapper extends BaseMapper<Message> {
+
+}

+ 65 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/PositionMapper.java

@@ -0,0 +1,65 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.dto.PositionDto;
+import com.copy.trade.entity.form.CopiedTradeForm;
+import com.copy.trade.entity.form.PositionForm;
+import com.copy.trade.entity.po.Position;
+import com.copy.trade.entity.vo.CopiedTradeVo;
+import com.copy.trade.entity.vo.PositionStatisticsVo;
+import com.copy.trade.entity.vo.PositionVo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import org.apache.ibatis.annotations.Param;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 跟单持仓表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-17
+ */
+public interface PositionMapper extends BaseMapper<Position> {
+
+    BigDecimal sumPrincipalAmount(@Param("customerId") Long customerId, @Param("traderId") Long traderId);
+    
+    Position getStudentPositionByTraderPositionId(@Param("traderPositionId") Long traderPositionId, @Param("customerId") Long customerId);
+
+    Boolean updateAvailablePosition(@Param("volume")BigDecimal volume,@Param("positionId") Long positionId);
+
+    List<Position> followPosition(String contractOrderEntrustId);
+
+    List<Position> followPositionByTraderPositionId(@Param("traderPositionId") Long traderPositionId);
+  
+    Position getTraderPosition(@Param("customerId")Long customerId,@Param("contractOrderEntrustId")String contractOrderEntrustId);
+
+    Boolean updateCurrentPosition(@Param("volume")BigDecimal volume, @Param("positionId")Long positionId,@Param("status") Integer status, @Param("closeTime") Long transactionTime);
+
+    List<Position> closedPositionList(@Param("traderId") Long traderId, @Param("startTime") Long startTime, @Param("endTime") Long endTime);
+    
+    List<Position> updatePositionList(@Param("traderId") Long traderId, @Param("startTime") Date startTime, @Param("endTime") Date endTime);
+
+    BigDecimal sumFollowAmount(Long traderId);
+    
+    BigDecimal sumFollowAmountToday(Long traderId,Long startTime);
+    
+    List<Position> sumPositionList(@Param("customerId") Long customerId, @Param("traderId") Long traderId);
+    
+    List<PositionDto> selectPositionStatusNot30All();
+    
+    List<PositionVo> page(@Param("page") Page page, @Param("positionForm") PositionForm positionForm);
+    
+    BigDecimal selectDividendFee(@Param("position")Position position);
+
+    BigDecimal selectCommission(@Param("position")Position position);
+    
+    BigDecimal selectStudentProfit(@Param("customerId") Long customerId, @Param("traderId") Long traderId);
+    
+    BigDecimal sumTotalFollowAmount();
+
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/RiskControlMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.RiskControl;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 跟单风险控制表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface RiskControlMapper extends BaseMapper<RiskControl> {
+
+}

+ 44 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/StatisticsDataMapper.java

@@ -0,0 +1,44 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.form.TraderDataQueryForm;
+import com.copy.trade.entity.po.StatisticsData;
+import com.copy.trade.entity.po.TraderData;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import org.apache.ibatis.annotations.Param;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 统计数据表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-29
+ */
+public interface StatisticsDataMapper extends BaseMapper<StatisticsData> {
+
+   StatisticsData  dataCount(@Param("traderId")Long traderId,@Param("startTime") String startTime);
+   
+   List<StatisticsData>  selectStatisticsData(@Param("traderId")Long traderId,@Param("startTime") String startTime);
+   
+   List<BigDecimal>  selectStatisticsDataNew(@Param("traderId")Long traderId,@Param("startTime") String startTime);
+   
+   List<StatisticsData>  selectStatisticsDataForRetractionRate14(@Param("traderId")Long traderId,@Param("startTime") String startTime);
+
+   BigDecimal earningsCount(@Param("traderId")Long traderId);
+   
+   BigDecimal earningsCountToday(@Param("traderId")Long traderId,@Param("startTime")Long startTime);
+   
+   BigDecimal balanceSort(@Param("traderId")Long traderId,@Param("startTime")String startTime,@Param("sort") String sort);
+   
+   List<StatisticsData> traderDataList(@Param("traderId") Long traderId);
+   
+   StatisticsData  recentStatisticsData(@Param("traderId")Long traderId);
+   
+   void updateMaxDateDate(@Param("traderId")Long traderId,@Param("yield14")BigDecimal yield14);
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/SymbolPriceMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.SymbolPrice;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 交易对实时价格 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-25
+ */
+public interface SymbolPriceMapper extends BaseMapper<SymbolPrice> {
+
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TagMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.Tag;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 标签表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+public interface TagMapper extends BaseMapper<Tag> {
+
+}

+ 27 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderDataMapper.java

@@ -0,0 +1,27 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.form.TraderDataQueryForm;
+import com.copy.trade.entity.form.TraderQueryForAdminForm;
+import com.copy.trade.entity.po.Customer;
+import com.copy.trade.entity.po.TraderData;
+import com.copy.trade.entity.vo.TraderDataVo;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+ * <p>
+ * 交易员统计数据 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-12-01
+ */
+public interface TraderDataMapper extends BaseMapper<TraderData> {
+	
+	List<TraderDataVo> traderDataList(@Param("page") Page page, @Param("traderDataQueryForm") TraderDataQueryForm traderDataQueryForm);
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderLevelMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.TraderLevel;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 交易员等级表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+public interface TraderLevelMapper extends BaseMapper<TraderLevel> {
+
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderSymbolMapper.java

@@ -0,0 +1,16 @@
+package com.copy.trade.dao;
+
+import com.copy.trade.entity.po.TraderSymbol;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 交易员带单合约 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface TraderSymbolMapper extends BaseMapper<TraderSymbol> {
+
+}

+ 19 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/dao/TraderTagMapper.java

@@ -0,0 +1,19 @@
+package com.copy.trade.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.copy.trade.entity.po.Tag;
+import com.copy.trade.entity.po.TraderTag;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 交易员标签表 Mapper 接口
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+public interface TraderTagMapper extends BaseMapper<TraderTag> {
+
+}

+ 32 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/ClosePositionDeal.java

@@ -0,0 +1,32 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class ClosePositionDeal implements Serializable {
+    private static final long serialVersionUID = -3839679778473819689L;
+
+    /**
+     * 平仓委托号
+     */
+    private String contractClosePositionEntrustNo;
+
+    /**
+     * 成交价格
+     */
+    private BigDecimal transactionPrice;
+
+    /**
+     * 成交金额
+     */
+    private BigDecimal transactionAmount;
+
+    /**
+     * 成交时间
+     */
+    private Long transactionTime;
+
+}

+ 27 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/CloseType.java

@@ -0,0 +1,27 @@
+package com.copy.trade.entity.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+@JsonFormat(shape = JsonFormat.Shape.NUMBER)
+public enum CloseType {
+    CLOSE(0, "平仓"),
+    MARKET_CLOSE(1, "市价全平"),
+    ONE_KEY_CLOSE(2, "一键平仓"),
+	REVERSE_OPEN(3, "反向开仓"),
+	CUT(4, "止盈止损"),
+	BLAST(5, "爆仓"),
+    ADMIN_CLOSE(6, "管理员平仓");
+
+    CloseType(int number, String description) {
+        this.code = number;
+        this.description = description;
+    }
+    private int code;
+    private String description;
+    public int getCode() {
+        return code;
+    }
+    public String getDescription() {
+        return description;
+    }
+}

+ 177 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/ContractOrderEntrust.java

@@ -0,0 +1,177 @@
+package com.copy.trade.entity.dto;
+
+
+import lombok.Data;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+
+@Data
+public class ContractOrderEntrust implements Serializable {
+	private static final Long serialVersionUID = 102L;
+
+    private Long id;
+
+    //合约ID
+    private Long contractId;
+
+    //用户ID
+    private Long memberId;
+    
+    private Long positionId;
+
+    //合约委托订单ID(自动生成)
+    private String contractOrderEntrustId;
+
+   //仓位模式(0全仓 1逐仓)
+    private String patterns;
+
+    //委托订单类型(0 开仓 1 平仓 | 与 direction 配合())
+    private String entrustType;
+
+    //方向(0买 1卖)
+    private String direction; // 0买 1卖
+
+    //委托类型(0市价 1限价 2计划委托)
+    private String type;
+
+    //交易对符号
+    private String symbol;
+
+    //币单位
+    private String coinSymbol;
+
+    //结算单位
+    private String baseSymbol;
+
+    // 触发价(委托方式是计划/限价必填)
+    private BigDecimal triggerPrice;
+
+    // 委托价(委托方式是计划/限价必填)
+    private BigDecimal entrustPrice;
+
+    // 触发价(委托方式是计划/限价必填)
+    private BigDecimal lossPrice;
+
+    // 委托价(委托方式是计划/限价必填)
+    private BigDecimal lossEntrustPrice;
+
+    // 触发价(委托方式是计划/限价必填)
+    private BigDecimal profitPrice;
+
+    // 委托价(委托方式是计划/限价必填)
+    private BigDecimal profitEntrustPrice;
+
+    //成交均价
+    private BigDecimal tradedPrice;
+
+    // 本金单位(如:USDT)
+    private String principalUnit;
+
+    //本金数量(冻结保证金)
+    private BigDecimal principalAmount;
+
+    //下单时价
+    private BigDecimal currentPrice;
+
+    //开仓手续费
+    private BigDecimal openFee;
+
+    //平仓手续费
+    private BigDecimal closeFee;
+
+    //合约面值
+    private BigDecimal shareNumber;
+
+    // 委托数量(张)
+    private BigDecimal volume;
+
+    // 成交数量(张)
+    private BigDecimal tradedVolume;
+
+    // 盈亏金额
+    private BigDecimal profitAndLoss;
+
+    //委托状态( 0:委托中/1:已撤销/2:委托失败/3:委托成功)
+    private String status;
+
+    //创建时间
+    private Long createTime;
+
+    //触发时间
+    private Long triggeringTime;
+
+    //是否是计划委托的委托单(0:否,1:是)
+    private int isFromSpot;
+
+    // 是否是爆仓单,0:否,1:是
+    private int isBlast;
+
+    // 是否已返佣,0:否,1:是
+    private int isReward;
+
+    // 是否是止盈止损单,0:否,1:是
+    private int isCut;
+
+    //是否是市价全平单,0:否,1:是
+    private int isMarketAllClose;
+
+    // 是否是限价成交单,0:否,1:是
+    private int isLimitPrice;
+
+    //开仓时间
+    private Long usdtOpenTime;
+
+    // 开仓均价(USDT本位)
+    private BigDecimal usdtOpenPrice;
+
+    // 是否是反向开仓单,0:否,1:是
+    private int isReversedOpen;
+
+    // 杠杆
+    private Integer leverage;
+
+    //成交时间
+    private Long dealTime;
+    
+    //仓位类型(0和仓 1分仓)
+    private String positionType;
+
+    //0USDT 1币本位
+    private String moneyType;
+
+   //开仓类型(0市价委托 1限价委托 2计划委托)
+    private Integer openType;
+
+    //平仓类型(0平仓 1市价全平 2一键平仓 3反向开仓 4止盈止损 5爆仓 6管理员平仓)
+	private String closeType;
+
+	//委托数量精度
+	private Integer decimalScale;
+	
+	private Integer isPercentage;
+	
+	private Integer violateTime;
+
+	//跟随订单ID 0为带单
+	private Long followId;
+
+	//跟单系统ID
+	private Long followSystemId;
+	
+	//强制平仓时的金额
+    private BigDecimal profitOrLoss;
+    //分润比例
+    private BigDecimal dividendPercent;
+
+    private Integer isSpecial;
+    
+    private BigDecimal percentageVolume;
+    
+    private BigDecimal minFollowAmount;
+    
+    private BigDecimal maxFollowAmount;
+    
+    private Integer isAdd;
+    private Long hedgeId;
+}

+ 37 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/EntrustCallback.java

@@ -0,0 +1,37 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 跟单委托回调消息(entrust-callback)实体类
+ */
+@Data
+public class EntrustCallback implements Serializable {
+
+    private static final long serialVersionUID = 6708527868840123433L;
+
+    /**
+     * 张数
+     */
+    private BigDecimal volume;
+
+    /**
+     * 跟单系统订单id
+     */
+    private  Long followSystemId;
+
+    /**
+     * 合约委托订单号
+     */
+    private  String contractOrderEntrustId;
+
+    /**
+     * 失败错误信息
+     */
+    private String error;
+
+
+}

+ 16 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/EntrustCancel.java

@@ -0,0 +1,16 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class EntrustCancel implements Serializable {
+
+    private static final long serialVersionUID = -1359404405655545972L;
+
+    /**
+     * 合约委托单号
+     */
+    private String contractOrderEntrustId;
+}

+ 53 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/EntrustDeal.java

@@ -0,0 +1,53 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class EntrustDeal implements Serializable {
+    private static final long serialVersionUID = -7839877503934930769L;
+
+    /**
+     * 合约委托订单号
+     */
+    private String contractOrderEntrustId;
+
+    /**
+     * 用户ID
+     */
+    private Long memberId;
+
+    /**
+     * 持仓方向(BUY多 SELL空)
+     */
+    private String direction;
+
+    /**
+     * 仓位ID
+     */
+    private Long positionId;
+
+    /**
+     * 开仓价格
+     */
+    private BigDecimal openPrice;
+
+    /**
+     * 持仓张数
+     */
+    private BigDecimal volume;
+
+    /**
+     * 保证金
+     */
+    private BigDecimal principalAmount;
+
+    /**
+     * 开仓时间
+     */
+    private Long openTime;
+
+
+}

+ 36 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/FollowClosePosition.java

@@ -0,0 +1,36 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class FollowClosePosition implements Serializable {
+    private static final long serialVersionUID = -7116679718212701806L;
+
+    /**
+     * 平仓委托单号
+     */
+    private String closePositionNo;
+
+    /**
+     * 持仓ID
+     */
+    private Long positionId;
+
+    /**
+     * 委托价格
+     */
+    private BigDecimal entrustPrice;
+
+    /**
+     * 委托类型(MARKET_PRICE市价, LIMIT_PRICE限价)
+     */
+    private String type;
+
+    /**
+     * 张数
+     */
+    private BigDecimal volume;
+}

+ 76 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/FollowEntrust.java

@@ -0,0 +1,76 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 跟单委托(follow-entrust消息实体类)
+ */
+@Data
+public class FollowEntrust implements Serializable {
+    private static final long serialVersionUID = 6708527868840122733L;
+
+    /**
+     * 跟单订单号(跟单系统生成)
+     */
+    private String copiedOrderNo;
+
+    /**
+     * 用户ID
+     */
+    private Long memberId;
+
+    /**
+     * 合约交易对ID
+     */
+    private Long contractId;
+
+    /**
+     * 交易对
+     */
+    private String symbol;
+
+    /**
+     * 委托类型(MARKET_PRICE限价 LIMIT_PRICE市价 SPOT_LIMIT计划委托)
+     */
+    private Integer type;
+
+    /**
+     * 委托方向(BUY做多 SELL做空)
+     */
+    private Integer direction;
+
+    /**
+     * 委托价格
+     */
+    private BigDecimal entrustPrice;
+
+    /**
+     * 杠杆倍数
+     */
+    private Integer leverage;
+
+    /**
+     * 止盈价
+     */
+    private BigDecimal profitPrice;
+
+    /**
+     * 止损价
+     */
+    private BigDecimal lossPrice;
+
+    /**
+     * 委托保证金
+     */
+    private BigDecimal principalAmount;
+
+    /**
+     * 计划委托触发价
+     */
+    private BigDecimal triggerPrice;
+
+
+}

+ 24 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/Message.java

@@ -0,0 +1,24 @@
+package com.copy.trade.entity.dto;
+
+import com.alibaba.fastjson.JSON;
+import com.copy.trade.enums.EntrustStatusEnum;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class Message implements Serializable {
+    private static final long serialVersionUID = -900274921680807928L;
+
+    /**
+     * 消息类型
+     *
+     */
+    private String type;
+
+    /**
+     * 消息
+     */
+    private String value;
+
+}

+ 57 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/PositionDto.java

@@ -0,0 +1,57 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class PositionDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+    /**
+     * 仓位ID
+     */
+    private Long positionId;
+
+    /**
+     * 交易对
+     */
+    private String symbol;
+    
+    /**
+     * 止损价格
+     */
+    private BigDecimal lossPrice;
+    
+    /**
+     * 止盈价格
+     */
+    private BigDecimal profitPrice;
+    
+    
+    /**
+     * 方向(10多 20空)
+     */
+    private Integer direction;
+
+    /**
+     * 保证金
+     */
+    private BigDecimal principalAmount;
+    
+    /**
+     * 止损比例下的亏损金额
+     */
+    private BigDecimal lossAmount;
+    
+    /**
+     * 止盈比例下的盈利金额
+     */
+    private BigDecimal profitAmount;
+
+
+
+}

+ 48 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/TraderClosePosition.java

@@ -0,0 +1,48 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class TraderClosePosition implements Serializable {
+
+    private static final long serialVersionUID = 1569955802752339314L;
+
+    /**
+     * 平仓委托价
+     */
+    private BigDecimal entrustPrice;
+
+    /**
+     * 仓位ID
+     */
+    private Long positionId;
+
+    /**
+     * 张数
+     */
+    private BigDecimal volume;
+
+    /**
+     * 平仓类型(CLOSE平仓 MARKET_CLOSE市价全平 ONE_KEY_CLOSE一键平仓 REVERSE_OPEN反向开仓 CUT_PROFIT止盈 CUT_LOSS止损 BLAST爆仓 ADMIN_CLOSE管理员强平)
+     */
+    private String closeType;
+
+    /**
+     * 委托时间
+     */
+    private Long entrustTime;
+
+    /**
+     * 合约平仓委托单号
+     */
+    private String contractClosePositionEntrustNo;
+
+    /**
+     * 委托类型(MARKET_PRICE市价, LIMIT_PRICE限价)
+     */
+    private String type;
+
+}

+ 100 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/dto/TraderOrder.java

@@ -0,0 +1,100 @@
+package com.copy.trade.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 交易员委托单(copy-trade消息实体类)
+ */
+@Data
+public class TraderOrder implements Serializable {
+    private static final long serialVersionUID = 6708827868849122733L;
+
+    /**
+     * 委托订单号
+     */
+    private String contractOrderEntrustId;
+
+    /**
+     * 用户id
+     */
+    private Long memberId;
+
+    /**
+     * 订单委托价格
+     */
+    private BigDecimal entrustPrice;
+
+    /**
+     * 委托张数
+     */
+    private BigDecimal quantity;
+
+    /**
+     * 保证金
+     */
+    private BigDecimal principalAmount;
+
+    /**
+     * 委托类型(LIMIT_PRICE限价 MARkET市价 TRIGGER计划委托)
+     */
+    private String type;
+
+    /**
+     * 杠杆倍数
+     */
+    private Integer leverage;
+
+    /**
+     * 交易对
+     */
+    private String symbol;
+
+    /**
+     * 合约ID
+     */
+    private Long contractId;
+
+    /**
+     * 订单方向(BUY做多 SELL做空)
+     */
+    private String direction;
+
+    /**
+     * 计划委托触发价
+     */
+    private BigDecimal triggerPrice;
+
+    /**
+     * 止损价
+     */
+    private BigDecimal stopLossPrice;
+
+    /**
+     * 止盈价
+     */
+    private BigDecimal stopProfitPrice;
+
+    /**
+     * 开仓时间
+     */
+    private Long createTime;
+
+    /**
+     * 委托状态(ENTRUST_ING委托中 ENTRUST_CANCEL已撤单 ENTRUST_FAILURE委托失败 ENTRUST_SUCCESS已成交)
+     */
+    private String status;
+
+    /**
+     * 成交价格(市价委托)
+     */
+    private BigDecimal tradedPrice;
+
+    /**
+     * 委托时间
+     */
+    private Long entrustTime;
+
+}

+ 21 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/AgentStudentPositionForm.java

@@ -0,0 +1,21 @@
+package com.copy.trade.entity.form;
+
+import java.util.List;
+
+import com.copy.trade.entity.base.BaseQueryForm;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class AgentStudentPositionForm extends BaseQueryForm {
+
+
+    @ApiModelProperty("老师ids")
+    private List<Long> teacherIds;
+    
+    @ApiModelProperty(name = "跟单状态(10跟随中 20用户消跟随 30被交易员移出)",allowableValues = "10,20,30")
+    private Integer status;
+}

+ 34 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/ClosePositionForm.java

@@ -0,0 +1,34 @@
+package com.copy.trade.entity.form;
+
+import com.copy.trade.entity.base.BaseQueryForm;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class ClosePositionForm extends BaseQueryForm {
+	
+	//@ApiModelProperty("学生ID")
+	//private Long customerId;
+
+	@ApiModelProperty("学生会员ID")
+    private Long customerMemberId;
+	
+	@ApiModelProperty("交易员会员ID")
+    private Long traderMemberId;
+	
+//	@ApiModelProperty("学生昵称")
+//    private String customerName ;
+//	
+//	@ApiModelProperty("老师昵称")
+//	private String traderName ;	
+
+	@ApiModelProperty("仓位id")
+	private Long positionId ;	
+	
+	@ApiModelProperty("平仓类型")
+	private Integer closeType ;	
+	
+}

+ 23 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/CopiedTradeForm.java

@@ -0,0 +1,23 @@
+package com.copy.trade.entity.form;
+
+import com.copy.trade.entity.base.BaseQueryForm;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class CopiedTradeForm extends BaseQueryForm {
+	@ApiModelProperty("用户会员ID")
+    private Long customerMemberId;
+	
+	@ApiModelProperty("交易员会员ID")
+    private Long traderMemberId;
+	
+	@ApiModelProperty("学生昵称")
+    private String customerName ;
+	
+	@ApiModelProperty("老师昵称")
+	private String traderName ;	
+}

+ 22 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/FollowConfigForm.java

@@ -0,0 +1,22 @@
+package com.copy.trade.entity.form;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class FollowConfigForm {
+
+	private Long id;
+
+	@ApiModelProperty("英文名")
+	private String configNameEn;
+
+	@ApiModelProperty("中文名")
+	private String configNameCn;
+
+	@ApiModelProperty("配置内容")
+	private String configContent;
+
+}

+ 28 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/PositionForm.java

@@ -0,0 +1,28 @@
+package com.copy.trade.entity.form;
+
+import com.copy.trade.entity.base.BaseQueryForm;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class PositionForm extends BaseQueryForm {
+	
+	@ApiModelProperty("学生会员ID")
+    private Long customerMemberId;
+	
+	@ApiModelProperty("交易员会员ID")
+    private Long traderMemberId;
+	
+	@ApiModelProperty("学生昵称")
+    private String customerName ;
+	
+	@ApiModelProperty("老师昵称")
+	private String traderName ;	
+
+	@ApiModelProperty("仓位id")
+	private Long positionId ;	
+	
+}

+ 23 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/StatisticsDataForm.java

@@ -0,0 +1,23 @@
+package com.copy.trade.entity.form;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.Min;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@ApiModel
+public class StatisticsDataForm {
+	
+	private Long id;
+
+    @ApiModelProperty("14日收益率")
+    private BigDecimal dayYield14;
+
+}

+ 39 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/StudentPositionForm.java

@@ -0,0 +1,39 @@
+package com.copy.trade.entity.form;
+
+import com.copy.trade.entity.base.BaseQueryForm;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class StudentPositionForm extends BaseQueryForm {
+
+
+    @ApiModelProperty("老师id")
+    private Long traderId;
+    
+    @ApiModelProperty("老师会员id")
+    private Long traderMemberId;
+    
+    @ApiModelProperty("是否有仓位:true-查询有仓位的,false为查询所有学生的")
+    private Boolean hasPosition;
+    
+    @ApiModelProperty("交易对  格式:ETH/USDT  BTC/USDT")
+    private String symbol;
+
+    @ApiModelProperty("方向(0-多 1-空)")
+    private Integer direction;
+    
+    @ApiModelProperty(name = "跟单状态(10跟随中 20用户消跟随 30被交易员移出)",allowableValues = "10,20,30")
+    private Integer status;
+    
+
+    @ApiModelProperty("学生会员Id")
+	private Long memberId;
+
+	@ApiModelProperty("学生昵称")
+	private String nickname;
+    
+}

+ 22 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TagForm.java

@@ -0,0 +1,22 @@
+package com.copy.trade.entity.form;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+
+@Data
+@ApiModel
+public class TagForm {
+	
+	private Long id;
+
+    @ApiModelProperty("中文名称")
+    @Length(min = 1, max = 10, message = "超过了最大长度")
+    private String name;
+
+    @ApiModelProperty("英文名称")
+    private String enName;
+
+}

+ 15 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderDataQueryForm.java

@@ -0,0 +1,15 @@
+package com.copy.trade.entity.form;
+
+import com.copy.trade.entity.base.BaseQueryForm;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class TraderDataQueryForm extends BaseQueryForm {
+
+    @ApiModelProperty("交易员id")
+    private Long traderId;
+
+}

+ 29 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderForm.java

@@ -0,0 +1,29 @@
+package com.copy.trade.entity.form;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@ApiModel
+@Data
+public class TraderForm {
+
+    
+    @ApiModelProperty("特级老师的最低跟随金额")
+    private Long  minFollowAmount;
+
+    @ApiModelProperty("修改老师统计数据开关")
+    private Boolean editDataSwitch ;
+
+    @ApiModelProperty("当前跟单默认人数")
+    private Long defaultFollowCustomer;
+    
+    @ApiModelProperty("默认的入住天数")
+    private Long defaultRegisterDays;
+
+    @ApiModelProperty("最高跟随金额")
+    private BigDecimal maxPrincipalAmount;
+
+}

+ 37 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderLevelForm.java

@@ -0,0 +1,37 @@
+package com.copy.trade.entity.form;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.Min;
+import java.math.BigDecimal;
+
+@Data
+@ApiModel
+public class TraderLevelForm {
+	
+	private Long id;
+
+    @ApiModelProperty("等级中文名称")
+    @Length(min = 1,max = 10,message = "超过最大字符长度")
+    private String name;
+
+    @ApiModelProperty("等级英文名称")
+    private String enName;
+
+    @ApiModelProperty("资产要求")
+    @DecimalMin(value = "1")
+    private BigDecimal asset;
+
+    @ApiModelProperty("最大跟随人数")
+    @Min(value = 1)
+    private Integer maxFollow;
+    
+    @ApiModelProperty("分润比例")
+    private BigDecimal dividendPercent;
+
+}

+ 24 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/form/TraderQueryForAdminForm.java

@@ -0,0 +1,24 @@
+package com.copy.trade.entity.form;
+
+import com.copy.trade.entity.base.BaseQueryForm;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class TraderQueryForAdminForm extends BaseQueryForm {
+
+    @ApiModelProperty("交易员等级")
+    private Long traderLevelId;
+    
+    @ApiModelProperty("会员id")
+    private Long memberId;
+    
+    @ApiModelProperty("昵称")
+    private String nickname;
+
+    @ApiModelProperty("是否顶级交易员(1是 2否)")
+    private Integer isTop;
+
+}

+ 85 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/ClosePositionVo.java

@@ -0,0 +1,85 @@
+package com.copy.trade.entity.vo;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("平仓记录")
+public class ClosePositionVo {
+
+	private Long id;
+
+	@ApiModelProperty("用户ID")
+	private Long customerId;
+
+	@ApiModelProperty("学生会员ID")
+	private Long customerMemberId;
+
+	@ApiModelProperty("交易员会员ID")
+	private Long traderMemberId;
+
+	@ApiModelProperty("学生昵称")
+	private String customerName;
+
+	@ApiModelProperty("老师昵称")
+	private String traderName;
+
+	@ApiModelProperty("仓位ID")
+	private Long positionId;
+
+	@ApiModelProperty("委托价格")
+	private BigDecimal entrustPrice;
+
+	@ApiModelProperty("平仓张数")
+	private BigDecimal quantity;
+
+	@ApiModelProperty("委托时间")
+	private Long entrustTime;
+
+	@ApiModelProperty("状态(0委托中 1已撤单 2委托失败 3已成交)")
+	private Integer status;
+
+	@ApiModelProperty("平仓类型(0平仓 1市价全平 2一键平仓 3反向开仓 4止盈止损 5爆仓 6管理员平仓 7跟单账户止盈 8跟单账号止损  9跟单仓位止盈 10跟单仓位止损 11跟单用户平仓")
+	private Integer closeType;
+
+	@ApiModelProperty("委托类型(1限价 0市价)")
+	private Integer type;
+
+	@ApiModelProperty("平仓委托单号")
+	private String closePositionNo;
+
+	@ApiModelProperty("合约委托单号")
+	private String contractOrderEntrustId;
+
+	@ApiModelProperty("跟随平仓委托单号")
+	private String copyContractOrderEntrustId;
+
+	@ApiModelProperty("交易手续费")
+	private BigDecimal transactionFee;
+
+	@ApiModelProperty("成交价格")
+	private BigDecimal transactionPrice;
+
+	@ApiModelProperty("成交金额")
+	private BigDecimal transactionAmount;
+
+	@ApiModelProperty("成交时间")
+	private Long transactionTime;
+
+	@ApiModelProperty("平仓委托失败原因")
+	private String error;
+
+	@ApiModelProperty("创建时间")
+	private Date createdTime;
+
+	@ApiModelProperty("更新时间")
+	private Date updatedTime;
+
+}

+ 59 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/CopiedTradeVo.java

@@ -0,0 +1,59 @@
+package com.copy.trade.entity.vo;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("跟单记录")
+public class CopiedTradeVo {
+	
+	private Long id;
+
+	@ApiModelProperty("用户ID")
+	private Long customerId;
+	@ApiModelProperty("用户昵称")
+	private String customerName;
+	@ApiModelProperty("用户会员ID")
+	private Long customerMemberId;
+	
+	@ApiModelProperty("交易员ID")
+	private Long traderId;
+	@ApiModelProperty("交易员昵称")
+	private String traderName;
+	@ApiModelProperty("交易员会员ID")
+	private Long traderMemberId;
+
+	@ApiModelProperty("交易对")
+	private String symbol;
+
+	@ApiModelProperty("方向(0多 1空)")
+	private Integer direction;
+	
+	@ApiModelProperty("杠杆")
+	private Integer leverage;
+
+	@ApiModelProperty("交易量")
+	private BigDecimal volume;
+
+	@ApiModelProperty("保证金")
+	private BigDecimal principalAmount;
+	
+	@ApiModelProperty("开仓价")
+	private BigDecimal openPrice;
+	
+	@ApiModelProperty("平仓价")
+	private BigDecimal closePrice;
+	
+	@ApiModelProperty("盈亏金额")
+	private BigDecimal profitAndLoss;
+
+	@ApiModelProperty("跟单时间")
+	private Long entrustTime;
+	
+	@ApiModelProperty("创建时间")
+	private Date createdTime;
+}

+ 87 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/CustomerVo.java

@@ -0,0 +1,87 @@
+package com.copy.trade.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+@Data
+@ApiModel
+public class CustomerVo implements Serializable {
+
+	@ApiModelProperty("用户昵称")
+    private String nickname;
+
+	@ApiModelProperty("头像")
+    private String avatar;
+
+	@ApiModelProperty("描述")
+    private String description;
+
+	@ApiModelProperty("是否是ID交易员(10不是 20交易员申请审核中 30交易员 40交易员申请不通过)")
+    private Integer trader;
+
+	@ApiModelProperty("最大亏损USDT")
+    private BigDecimal maxLoss;
+
+	@ApiModelProperty("最大盈利USDT")
+    private BigDecimal maxProfit;
+
+	@ApiModelProperty("doge会员ID")
+    private Long memberId;
+
+	@ApiModelProperty("自动取消跟随开关(1关闭 2开启)")
+    private Boolean automaticUnfollow;
+
+	@ApiModelProperty("交易员等级ID")
+    private Long traderLevelId;
+
+	@ApiModelProperty("合约资产")
+    private BigDecimal balance;
+
+	@ApiModelProperty("成为交易员时间")
+    private Date traderTime;
+    
+	@ApiModelProperty("最低跟随金额")
+    private Long  minFollowAmount;
+    
+	@ApiModelProperty("当前跟单配置人数")
+    private Long  defaultFollowCustomer;
+    
+	@ApiModelProperty("改老师统计数据开关")
+    private Boolean editDataSwitch ;
+    
+	@ApiModelProperty("默认入住天数")
+    private Long defaultRegisterDays;
+    
+	@ApiModelProperty("id")
+    private Long id;
+
+	@ApiModelProperty("创建时间")
+    private Date createdTime;
+
+	@ApiModelProperty("更新时间")
+    private Date updatedTime;
+	
+	@ApiModelProperty("当前跟单实际人数")
+    private Long  followCustomer;
+	
+	@ApiModelProperty("取消跟单人数")
+	private Integer cancelFollowerCustomer;
+	
+	@ApiModelProperty("移除跟单人数")
+	private Integer removeFollowerCustomer;
+
+	@ApiModelProperty("是否顶级交易员(1是 2否)")
+	private Integer isTop;
+
+	@ApiModelProperty("最高跟随金额")
+	private BigDecimal maxPrincipalAmount;
+
+}

+ 24 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/FolloweInforAgentVo.java

@@ -0,0 +1,24 @@
+package com.copy.trade.entity.vo;
+
+import java.util.List;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel("代理商的跟单信息")
+@Data
+public class FolloweInforAgentVo {
+	
+    
+	@ApiModelProperty("取消跟单人数")
+	private Integer cancelFollowerCustomer;
+	
+	@ApiModelProperty("移除跟单人数")
+	private Integer removeFollowerCustomer;
+	
+	@ApiModelProperty("老师ids")
+	private List<Long> teacherIds;
+
+    
+}

+ 58 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/FollowerAgentVo.java

@@ -0,0 +1,58 @@
+package com.copy.trade.entity.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@ApiModel("我的学生")
+@Data
+public class FollowerAgentVo {
+	
+	@ApiModelProperty("id")
+    private Long id;
+	
+	@ApiModelProperty("memberId")
+	private Long memberId;
+
+	@ApiModelProperty("昵称")
+	private String nickname;
+
+	@ApiModelProperty("账号")
+    private String username;
+	
+	@ApiModelProperty("老师id")
+	private Long teacherId;
+	
+	@ApiModelProperty("老师memberId")
+	private Long teacherMemberId;
+	
+	@ApiModelProperty("老师昵称")
+	private String teacherNickname;
+	
+	@ApiModelProperty("老师账号")
+	private String teacherUsername;
+
+    @ApiModelProperty("账户总余额")
+    private BigDecimal totalAccountBalance;
+
+    @ApiModelProperty("资产账户")
+    private BigDecimal assetAccount;
+
+    @ApiModelProperty("合约账户")
+    private BigDecimal contractAccount;
+    
+    @ApiModelProperty("跟单账户")
+    private BigDecimal followAccount;
+    
+    @ApiModelProperty("跟单总盈亏")
+    private BigDecimal followAllprofitOrLoss;
+    
+    @ApiModelProperty("跟随时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    private Date followTime;
+    
+}

+ 51 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/FollowerVo.java

@@ -0,0 +1,51 @@
+package com.copy.trade.entity.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@ApiModel("我的学生")
+@Data
+public class FollowerVo {
+
+	@ApiModelProperty("id")
+    private Long id;
+
+	@ApiModelProperty("memberId")
+	private Long memberId;
+
+	@ApiModelProperty("昵称")
+	private String nickname;
+
+	@ApiModelProperty("账号")
+    private String username;
+
+    @ApiModelProperty("账户总余额")
+    private String totalAccountBalance;
+
+    @ApiModelProperty("资产账户")
+    private String assetAccount;
+
+    @ApiModelProperty("合约账户")
+    private String contractAccount;
+
+    @ApiModelProperty("跟单账户")
+    private String followAccount;
+
+    @ApiModelProperty("跟单总盈亏")
+    private String followAllprofitOrLoss;
+
+    @ApiModelProperty("本单盈亏")
+    private String profitOrLoss;
+
+    @ApiModelProperty("跟随时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    private Date followTime;
+    
+    @ApiModelProperty("是否有跟随仓位")
+    private Boolean hasPosition;
+    
+}

+ 20 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/PositionStatisticsVo.java

@@ -0,0 +1,20 @@
+package com.copy.trade.entity.vo;
+
+import java.math.BigDecimal;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("仓位统计")
+public class PositionStatisticsVo {
+
+
+	@ApiModelProperty("跟单累计跟随")
+	private BigDecimal totalFollowAmount;
+
+	@ApiModelProperty("跟单分润汇总")
+	private BigDecimal totalDividendFee;
+
+}

+ 100 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/PositionVo.java

@@ -0,0 +1,100 @@
+package com.copy.trade.entity.vo;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("跟单记录")
+public class PositionVo {
+
+	private Long id;
+	
+	@ApiModelProperty("学生会员ID")
+	private Long customerMemberId;
+
+	@ApiModelProperty("交易员会员ID")
+	private Long traderMemberId;
+
+	@ApiModelProperty("学生昵称")
+	private String customerName;
+
+	@ApiModelProperty("老师昵称")
+	private String traderName;
+
+	@ApiModelProperty("用户ID")
+	private Long customerId;
+
+	@ApiModelProperty("仓位ID")
+	private Long positionId;
+
+	@ApiModelProperty("交易员ID")
+	private Long traderId;
+
+	@ApiModelProperty("交易对")
+	private String symbol;
+
+	@ApiModelProperty("方向(10多 20空)")
+	private Integer direction;
+
+	@ApiModelProperty("杠杆倍数")
+	private Integer leverage;
+
+	@ApiModelProperty("开仓价格")
+	private BigDecimal openPrice;
+
+	@ApiModelProperty("总持仓张数")
+	private BigDecimal totalPosition;
+
+	@ApiModelProperty("总本金")
+	private BigDecimal totalPrincipalAmount;
+
+	@ApiModelProperty("当前可平张数")
+	private BigDecimal availablePosition;
+
+	@ApiModelProperty("当前持仓张数")
+	private BigDecimal currentPosition;
+
+	@ApiModelProperty("保证金")
+	private BigDecimal principalAmount;
+
+	@ApiModelProperty("合约委托单号")
+	private String contractOrderEntrustId;
+
+	@ApiModelProperty("持仓状态(10未平仓 20部分平仓 30全部平仓)")
+	private Integer status;
+
+	@ApiModelProperty("交易手续费")
+	private BigDecimal transactionFee;
+
+	@ApiModelProperty("开仓时间")
+	private Long openTime;
+
+	@ApiModelProperty("平仓时间")
+	private Long closeTime;
+
+	@ApiModelProperty("平仓均价")
+	private BigDecimal closePrice;
+
+	@ApiModelProperty("盈亏金额")
+	private BigDecimal profitAndLoss;
+
+	@ApiModelProperty("分润金额")
+	private BigDecimal dividendFee;
+
+	@ApiModelProperty("老师仓位ID")
+	private Long traderPositionId;
+
+	@ApiModelProperty("创建时间")
+	private Date createdTime;
+
+	@ApiModelProperty("更新时间")
+	private Date updatedTime;
+
+}

+ 20 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/TagVo.java

@@ -0,0 +1,20 @@
+package com.copy.trade.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+@Data
+@ApiModel
+public class TagVo {
+
+    @ApiModelProperty("标签ID")
+    private Long id;
+
+    @ApiModelProperty("标签名称")
+    private String name;
+
+    @ApiModelProperty("英文名称")
+    private String enName;
+}

+ 76 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/entity/vo/TraderDataVo.java

@@ -0,0 +1,76 @@
+package com.copy.trade.entity.vo;
+
+import java.math.BigDecimal;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.copy.trade.entity.base.BasePo;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class TraderDataVo {
+
+
+    private Long traderId;
+
+    /**
+     * 14日收益率
+     */
+    private BigDecimal dayYield14;
+
+    /**
+     * 30日收益率
+     */
+    private BigDecimal dayYield30;
+
+    /**
+     * 14日胜率
+     */
+    private BigDecimal winRate14;
+
+    /**
+     * 累积盈利额
+     */
+    private BigDecimal profitAmount;
+
+    /**
+     * 累积跟随人数
+     */
+    private Long followCustomer;
+
+    /**
+     * 14日成交单量
+     */
+    private Long orderDeal14;
+
+    /**
+     * 14日最大回撤率
+     */
+    private BigDecimal retractionRate14;
+
+    /**
+     * 累积交易天数
+     */
+    private Long tradingDays;
+
+    /**
+     * 累积盈利天数
+     */
+    private Long profitDays;
+
+    /**
+     * 本月跟随人数
+     */
+    private Long currentMonthFollow;
+    
+    /**
+     * 14日团队盈利
+     */
+    private BigDecimal teamProfit14;
+    
+    private String nickname;
+    
+    
+
+}

+ 46 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/filter/CrossDomainFilter.java

@@ -0,0 +1,46 @@
+package com.copy.trade.filter;
+
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+@Order() //过滤器加载的顺序 默认Integer.MAXVALUE
+@WebFilter(urlPatterns = "/*",filterName = "crossDomainFilter")
+public class CrossDomainFilter implements Filter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
+        //设置跨域请求
+        HttpServletResponse response = (HttpServletResponse) resp;
+        HttpServletRequest request = (HttpServletRequest) req;
+        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); //解决跨域访问报错
+        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
+        response.setHeader("Access-Control-Max-Age", "3628800"); //设置过期时间
+        response.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Access-Control-Allow-Origin,Content-Type,Accept,client_id,token,EX-SysAuthToken,EX-JSESSIONID,Accept-Language,Authorization");
+        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // 支持HTTP 1.1.
+        response.setHeader("Access-Control-Allow-Credentials", "true");
+        response.setHeader("Pragma", "no-cache"); // 支持HTTP 1.0. response.setHeader("Expires", "0");
+        if(request.getMethod().equals("OPTIONS")){
+            response.setStatus(200);
+            return;
+        }
+        chain.doFilter(req, resp);
+
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}

+ 52 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/interceptor/AuthenticationInterceptor.java

@@ -0,0 +1,52 @@
+package com.copy.trade.interceptor;
+
+
+import com.copy.trade.constant.DogeApi;
+import com.copy.trade.entity.po.Customer;
+import com.copy.trade.service.ICustomerService;
+import com.copy.trade.util.WebAssert;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+@Slf4j
+@Component
+public class AuthenticationInterceptor implements HandlerInterceptor {
+
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        // 非controller请求直接跳过
+        if (!(handler instanceof HandlerMethod)) {
+            return true;
+        }
+        //String tokenHeader = request.getHeader(DogeApi.TOKEN_NAME);
+        //boolean hasAuth = !StringUtils.isBlank(tokenHeader);
+        //WebAssert.hasAuth(hasAuth, "4001");
+        //Object admin = request.getSession().getAttribute(DogeApi.SESSION_ADMIN);
+		/*
+		 * log.info("admin={}", admin); if(admin != null) { //验证登陆 return true; } else {
+		 * return true; }
+		 */
+        return true;
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+
+    }
+
+}

+ 49 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/IClosePositionService.java

@@ -0,0 +1,49 @@
+package com.copy.trade.service;
+
+import com.copy.trade.entity.dto.ClosePositionDeal;
+import com.copy.trade.entity.dto.ContractOrderEntrust;
+import com.copy.trade.entity.dto.EntrustCallback;
+import com.copy.trade.entity.dto.TraderClosePosition;
+import com.copy.trade.entity.form.ClosePositionForm;
+import com.copy.trade.entity.form.PositionForm;
+import com.copy.trade.entity.po.ClosePosition;
+import com.copy.trade.entity.vo.ClosePositionVo;
+import com.copy.trade.entity.vo.PositionVo;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 平仓记录 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-22
+ */
+public interface IClosePositionService extends IService<ClosePosition> {
+
+    Boolean traderClosePosition(TraderClosePosition traderClosePosition);
+    
+    public Integer traderClosePositionSuccess(ContractOrderEntrust contractOrderEntrust);
+
+    Boolean followClosePositionCallback(ContractOrderEntrust contractOrderEntrust);
+
+    Boolean cancel(String contractClosePositionEntrustNo);
+
+    Boolean closePositionDeal(ClosePositionDeal closePositionDeal);
+
+    List<ClosePosition> closePositionByPositionId(Long positionId);
+    
+    Page<ClosePositionVo> list(ClosePositionForm closePositionForm);
+
+    void processCloseRetryQueue();
+
+    Integer doClosePositionDB(ContractOrderEntrust contractOrderEntrust);
+
+    /**
+     * 开仓数据丢失时,重建开仓+平仓组合记录(直接写入 DONE 状态的 Position 和成功的 ClosePosition)
+     */
+    void reconstructOpenAndClose(ContractOrderEntrust contractOrderEntrust);
+}

+ 64 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/ICopiedTradeService.java

@@ -0,0 +1,64 @@
+package com.copy.trade.service;
+
+import com.copy.trade.entity.dto.ContractOrderEntrust;
+import com.copy.trade.entity.dto.EntrustCallback;
+import com.copy.trade.entity.dto.EntrustCancel;
+import com.copy.trade.entity.dto.TraderOrder;
+import com.copy.trade.entity.form.CopiedTradeForm;
+import com.copy.trade.entity.po.CopiedTrade;
+import com.copy.trade.entity.vo.CopiedTradeVo;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * <p>
+ * 跟单记录表 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface ICopiedTradeService extends IService<CopiedTrade> {
+
+    Integer TRADER_ORDER = 10;
+
+    Integer COPY_ORDER = 20;
+
+    /**
+     * 跟单
+     * @param traderOrder
+     * @return
+     */
+    Boolean copyTrade(ContractOrderEntrust traderOrder);
+
+    /**
+     * 跟单回调
+     * @param entrustCallback
+     * @return
+     */
+    Boolean entrustCallback(ContractOrderEntrust entrustCallback);
+
+    CopiedTrade getByContractOrderEntrustId(String contractOrderEntrustId);
+
+    /**
+     * 撤单
+     * @param entrustCancel
+     * @return
+     */
+    Boolean entrustCancel(EntrustCancel entrustCancel);
+    
+    
+    Boolean entrustFollowOpenfail(ContractOrderEntrust entrustCallback);
+
+    /**
+     * 批量跟单回调(批量开仓完成后的DB操作,替代逐条调用 entrustCallback)
+     */
+    Boolean entrustCallbackBatch(List<ContractOrderEntrust> orders);
+    
+    Page<CopiedTradeVo> list(CopiedTradeForm copiedTradeForm);
+
+}

+ 24 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/ICustomerFollowSymbolService.java

@@ -0,0 +1,24 @@
+package com.copy.trade.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.copy.trade.entity.po.CustomerFollowSymbol;
+import com.copy.trade.entity.po.TraderSymbol;
+import lombok.Getter;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 用户跟随交易对 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface ICustomerFollowSymbolService extends IService<CustomerFollowSymbol> {
+
+    List<CustomerFollowSymbol> listByTraderAndSymbol(Long traderId,String symbol);
+
+    Boolean offFollowSymbol(Long customerId, Long traderId);
+}

+ 50 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/ICustomerService.java

@@ -0,0 +1,50 @@
+package com.copy.trade.service;
+
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.copy.trade.entity.form.TraderForm;
+import com.copy.trade.entity.form.TraderQueryForAdminForm;
+import com.copy.trade.entity.po.Customer;
+import com.copy.trade.entity.vo.CustomerVo;
+import com.copy.trade.entity.vo.TraderTotalVo;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 用户表 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface ICustomerService extends IService<Customer> {
+
+    Customer getByMemberId(Long memberId);
+
+    Boolean approvalTrader(Long traderId, Long levelId);
+
+    Boolean reject(Long traderId);
+
+    Boolean automaticUnfollow();
+    
+    Boolean cancelTrader(Long traderId);
+    
+    Boolean synchronousTraderInfor();
+    
+    Boolean updateTraderLevelId(Long traderId, Long traderLevelId);
+
+    Boolean updateTraderTop(Long traderId, Integer isTop);
+
+    List<Customer> traderList();
+    
+    Page<Customer> applyList(Page page);
+    
+    Page<CustomerVo> traderList(TraderQueryForAdminForm traderQueryForAdminForm);
+    
+    Page<TraderTotalVo> traderTotalList(TraderQueryForAdminForm traderQueryForAdminForm);
+    
+    Boolean updateTraderParams(Long traderId, TraderForm traderForm);
+}

+ 17 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/IFavoriteService.java

@@ -0,0 +1,17 @@
+package com.copy.trade.service;
+
+import com.copy.trade.entity.po.Favorite;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 关注表 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface IFavoriteService extends IService<Favorite> {
+
+
+}

+ 30 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/IFollowConfigService.java

@@ -0,0 +1,30 @@
+package com.copy.trade.service;
+
+import com.copy.trade.entity.form.FollowConfigForm;
+import com.copy.trade.entity.po.Follow;
+import com.copy.trade.entity.po.FollowConfig;
+import com.copy.trade.entity.po.Tag;
+import com.copy.trade.enums.FollowStatusEnum;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 标签表 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-12
+ */
+public interface IFollowConfigService extends IService<FollowConfig> {
+
+	FollowConfig getConfig(String configNameEn);
+	
+	Boolean editById(FollowConfigForm followConfigForm);
+	
+	List<FollowConfig> getListForAdmin();
+
+}

+ 55 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/IFollowService.java

@@ -0,0 +1,55 @@
+package com.copy.trade.service;
+
+
+import com.copy.trade.entity.form.AgentStudentPositionForm;
+import com.copy.trade.entity.form.StudentPositionForm;
+import com.copy.trade.entity.po.Follow;
+import com.copy.trade.entity.vo.FolloweInforAgentVo;
+import com.copy.trade.entity.vo.FollowerAgentVo;
+import com.copy.trade.entity.vo.FollowerVo;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.copy.trade.enums.FollowStatusEnum;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.web.bind.annotation.RequestParam;
+
+
+/**
+ * <p>
+ * 跟随表 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-08
+ */
+public interface IFollowService extends IService<Follow> {
+
+    List<Follow> getByCustomerId(Long customerId);
+
+    Boolean unfollow(Follow follow, FollowStatusEnum followStatusEnum);
+
+    Integer countByTrader(Long traderId, String startTime);
+    
+    Integer countByTraderAndByEndTime(Long traderId, Date endTime);
+    
+    Integer countByTraderToday(Long traderId, Date startTime);
+
+    Integer followerCount(Long traderId);
+    
+    Integer followerCountByStatus(Long traderId, FollowStatusEnum followStatusEnum);
+    
+    List<Long> followering(Long traderId);
+    
+    Page<FollowerVo> followers(StudentPositionForm studentPositionForm);
+    
+    Page<FollowerAgentVo> followersAgent(AgentStudentPositionForm studentPositionForm);
+    
+    FolloweInforAgentVo selectFollowInforAgent(String subIds);
+    
+    Boolean removeFollow(Long customerId,Long traderId);
+    
+
+}

+ 18 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/IKafkaMessageService.java

@@ -0,0 +1,18 @@
+package com.copy.trade.service;
+
+import com.copy.trade.entity.po.KafkaMessage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * kafka消息发送 服务类
+ * </p>
+ *
+ * @author wz
+ * @since 2022-11-22
+ */
+public interface IKafkaMessageService extends IService<KafkaMessage> {
+
+    void messageSend();
+
+}

+ 15 - 0
copy/copy-trade-admin/src/main/java/com/copy/trade/service/IMessageService.java

@@ -0,0 +1,15 @@
+package com.copy.trade.service;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.copy.trade.entity.po.Message;
+import com.copy.trade.enums.MessageTypeEnum;
+
+public interface IMessageService extends IService<Message> {
+
+	boolean saveMessage(Long customerId, String symbol, MessageTypeEnum messageType, BigDecimal volume, BigDecimal triggerPrice, BigDecimal dealPrice,String content,Long date);
+	
+	boolean saveMessage(Message message);
+}

部分文件因文件數量過多而無法顯示