From 65fbbf04892c6864906670033a9bffec1f7911c7 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Mon, 01 Jun 2026 18:07:37 +0800
Subject: [PATCH] 初始化
---
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java | 760 ++++++++++++++++
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientManager.java | 209 ++--
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java | 282 ++++++
src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxGridChannelHandler.java | 30
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridElement.java | 293 ++++++
src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java | 16
src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ResponseHandler.java | 2
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTraderParam.java | 102 ++
src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/RequestBuilder.java | 2
src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxKlineChannelHandler.java | 83 +
src/main/resources/application-test.yml | 2
pom.xml | 60 -
src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java | 6
/dev/null | 14
src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java | 89 +
src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/FebsException.java | 15
src/main/java/com/xcong/excoin/modules/okxNewPrice/ExchangeInfoEnum.java | 73 +
src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java | 3
src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/SSLConfig.java | 22
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxConfig.java | 182 +++
src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java | 58 -
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java | 383 ++++++++
src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java | 89 +
23 files changed, 2,524 insertions(+), 251 deletions(-)
diff --git a/pom.xml b/pom.xml
index 885db64..f10809c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,14 +36,6 @@
<dependencies>
- <!-- Source: https://mvnrepository.com/artifact/io.gate/gate-api -->
- <dependency>
- <groupId>io.gate</groupId>
- <artifactId>gate-api</artifactId>
- <version>7.2.71</version>
- <scope>compile</scope>
- </dependency>
-
<dependency>
<groupId>ripple</groupId>
<artifactId>ripple</artifactId>
@@ -61,13 +53,6 @@
<dependency>
- <groupId>org.web3j</groupId>
- <artifactId>core</artifactId>
- <version>4.5.5</version>
- </dependency>
-
-
- <dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<!-- <version>3.6.0</version>-->
@@ -78,19 +63,6 @@
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>3.6.0</version>
- </dependency>
-
- <!-- https://mvnrepository.com/artifact/org.web3j/parity -->
- <dependency>
- <groupId>org.web3j</groupId>
- <artifactId>parity</artifactId>
- <version>4.5.10</version>
- <exclusions>
- <exclusion>
- <artifactId>core</artifactId>
- <groupId>org.web3j</groupId>
- </exclusion>
- </exclusions>
</dependency>
<dependency>
@@ -184,18 +156,6 @@
<version>${mysql-driver.version}</version>
</dependency>
- <dependency>
- <groupId>org.web3j</groupId>
- <artifactId>core</artifactId>
- <version>4.5.5</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.web3j/parity -->
- <dependency>
- <groupId>org.web3j</groupId>
- <artifactId>parity</artifactId>
- <version>4.5.10</version>
- </dependency>
-
<!-- 参数校验 start -->
<dependency>
<groupId>javax.validation</groupId>
@@ -268,31 +228,11 @@
<dependency>
- <groupId>io.netty</groupId>
- <artifactId>netty-all</artifactId>
- <version>${netty.version}</version>
- </dependency>
-
- <dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
- <dependency>
- <groupId>com.aliyun.oss</groupId>
- <artifactId>aliyun-sdk-oss</artifactId>
- <version>${aliyun-oss.version}</version>
- </dependency>
-
- <dependency>
- <groupId>com.huobi.sdk</groupId>
- <artifactId>huobi-client</artifactId>
- <version>1.0.8-SNAPSHOT</version>
- <scope>system</scope>
- <systemPath>${basedir}/lib/huobi-client-1.0.8-SNAPSHOT.jar</systemPath>
- </dependency>
-
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
diff --git a/src/main/java/com/xcong/excoin/common/LoginUserUtils.java b/src/main/java/com/xcong/excoin/common/LoginUserUtils.java
deleted file mode 100644
index a59ba96..0000000
--- a/src/main/java/com/xcong/excoin/common/LoginUserUtils.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.xcong.excoin.common;
-
-import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.exception.GlobalException;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.utils.RedisUtils;
-import com.xcong.excoin.utils.SpringContextHolder;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpRequest;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-
-/**
- * 登陆用户工具类
- *
- * @author wzy
- * @date 2020-05-14
- **/
-@Slf4j
-public class LoginUserUtils {
-
- private static final String ANON = "anonymousUser";
-
- public static MemberEntity getAppLoginUser() {
- if (SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals(ANON)) {
- throw new GlobalException("无法获取登陆信息");
- } else {
- return (MemberEntity) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- }
- }
-
- public static String getAppLoginUserToken() {
- return (String) SecurityContextHolder.getContext().getAuthentication().getCredentials();
- }
-
- public static void resetAppLoginUser(MemberEntity memberEntity) {
- String token = getAppLoginUserToken();
- RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
- String jsonStr = redisUtils.getString(AppContants.PC_LOGIN_PREFIX + token);
- if (StrUtil.isNotBlank(jsonStr)) {
- redisUtils.set(AppContants.PC_LOGIN_PREFIX + token, JSONObject.toJSONString(memberEntity));
- } else {
- redisUtils.set(AppContants.APP_LOGIN_PREFIX + token, JSONObject.toJSONString(memberEntity));
- }
- }
-
- /**
- * mybatis 拦截器专用
- *
- * @return MemberEntity
- */
- public static MemberEntity getUser() {
- if (SecurityContextHolder.getContext().getAuthentication() == null) {
- return null;
- }
-
- if (SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals(ANON)) {
- return null;
- } else {
- return (MemberEntity) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- }
- }
-
- public static boolean isBrowser(HttpServletRequest request) {
- String userAgent = request.getHeader("user-agent");
- if (userAgent.toLowerCase().contains("mobile") || userAgent.contains("CFNetwork") || userAgent.toLowerCase().contains("okhttp")) {
- return false;
- }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java b/src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java
deleted file mode 100644
index 79c0ff1..0000000
--- a/src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.xcong.excoin.common.system.base;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * @author wzy
- * @date 2020-04-24 14:58
- **/
-@Data
-public class BaseEntity implements Serializable {
- private static final long serialVersionUID = 1L;
-
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
-
- private String createBy;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date createTime;
-
- private String updateBy;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date updateTime;
-
- private Integer version;
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/base/IBaseService.java b/src/main/java/com/xcong/excoin/common/system/base/IBaseService.java
deleted file mode 100644
index f11cae2..0000000
--- a/src/main/java/com/xcong/excoin/common/system/base/IBaseService.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xcong.excoin.common.system.base;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * @author wzy
- */
-public interface IBaseService<T> extends IService<T> {
- T findById(Object id);
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java b/src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java
deleted file mode 100644
index 0924317..0000000
--- a/src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.xcong.excoin.common.system.bean;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-12
- **/
-@Getter
-@AllArgsConstructor
-public class LoginUserBean implements UserDetails {
-
- private final MemberEntity memberEntity;
-
- private final List<Long> roles;
-
- private final List<GrantedAuthority> authorities;
-
- @JsonIgnore
- @Override
- public String getPassword() {
- return memberEntity.getPassword();
- }
-
- @JsonIgnore
- @Override
- public String getUsername() {
- return "";
- }
-
- @JsonIgnore
- @Override
- public boolean isAccountNonExpired() {
- return true;
- }
-
- @JsonIgnore
- @Override
- public boolean isAccountNonLocked() {
- return true;
- }
-
- @JsonIgnore
- @Override
- public boolean isCredentialsNonExpired() {
- return true;
- }
-
- @JsonIgnore
- @Override
- public boolean isEnabled() {
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/controller/CommonController.java b/src/main/java/com/xcong/excoin/common/system/controller/CommonController.java
deleted file mode 100644
index 61639f7..0000000
--- a/src/main/java/com/xcong/excoin/common/system/controller/CommonController.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.xcong.excoin.common.system.controller;
-
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.dto.Base64UploadDto;
-import com.xcong.excoin.common.system.service.CommonService;
-import com.xcong.excoin.configurations.properties.AliOssProperties;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import com.xcong.excoin.utils.OssUtils;
-import com.xcong.excoin.utils.RedisUtils;
-import com.xcong.excoin.utils.SmsUtils;
-import com.xcong.excoin.utils.mail.Sms106Send;
-import com.xcong.excoin.utils.mail.SmsSend;
-import com.xcong.excoin.utils.mail.SubMailSend;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 公共请求类
- *
- * @author wzy
- * @date 2020-05-18
- **/
-@Slf4j
-@Api(value = "公共请求类", tags = "公共请求类")
-@RestController
-@RequestMapping(value = "/common")
-public class CommonController {
-
- private static final String SUCCESS = "Success";
-
- @Resource
- private RedisUtils redisUtils;
-
- @Resource
- private CommonService commonservice;
-
- @Resource
- private AliOssProperties aliOssProperties;
-
- @ApiOperation(value = "获取验证码接口", notes = "获取验证码通用接口")
- @GetMapping(value = "/verifyCode")
- public Result verifyCode(@ApiParam(name = "account", value = "手机号或邮箱", required = true) @RequestParam(value = "account") String account,
- @ApiParam(name = "type", value = "类型1-手机号2-邮箱", required = true) @RequestParam("type") String type) {
- log.info("#账号:{}, 类型:{}#", account, type);
-
- Integer code = (int) ((Math.random() * 9 + 1) * 100000);
- if (StrUtil.isNotBlank(redisUtils.getString(AppContants.VERIFY_CODE_PREFIX + account))) {
- return Result.fail(MessageSourceUtils.getString("common_verify_code_exist"));
- }
-
- // 发送手机验证码
- if (AppContants.ACCOUNT_TYPE_MOBILE.equals(type)) {
- boolean result = Sms106Send.sendVerifyCode(account, code.toString(), 2);
- if (result) {
- Map<String, Object> map = new HashMap<>();
- boolean flag = redisUtils.set(AppContants.VERIFY_CODE_PREFIX + account, code, 120);
- map.put("code", flag);
- return Result.ok(MessageSourceUtils.getString("member_service_0010"), map);
- }
- // 发送邮件验证码
- } else if (AppContants.ACCOUNT_TYPE_EMAIL.equals(type)) {
- boolean flag = SubMailSend.sendMail(account, code.toString());
- if (flag) {
- redisUtils.set(AppContants.VERIFY_CODE_PREFIX + account, code, 120);
- return Result.ok(MessageSourceUtils.getString("member_service_0010"));
- } else {
- return Result.fail(MessageSourceUtils.getString("result_fail_msg"));
- }
- } else {
- log.info("未定义账号类型");
- return Result.fail(MessageSourceUtils.getString("result_fail_msg"));
- }
- return Result.fail(MessageSourceUtils.getString("result_fail_msg"));
- }
-
- @ApiOperation(value = "验证验证码是否正确", notes = "验证验证码是否正确")
- @GetMapping(value = "/checkVerify")
- public Result checkVerify(@ApiParam(name = "account", value = "账号", required = true) @RequestParam("account") String account,
- @ApiParam(name = "code", value = "验证码", required = true) @RequestParam("code") String code) {
- boolean flag = commonservice.verifyCode(account, code);
- if (flag) {
- return Result.ok(MessageSourceUtils.getString("result_success_msg"));
- }
- return Result.fail(MessageSourceUtils.getString("common_verify_code"));
- }
-
- @ApiOperation(value = "文件上次接口", notes = "文件上传")
- @PostMapping(value = "/uploadFileBase64")
- public Result uploadFileBase64(@RequestBody @Validated Base64UploadDto uploadDto) {
- String imageName = "uploadeFile/image/" + System.currentTimeMillis() + IdUtil.simpleUUID() + AppContants.UPLOAD_IMAGE_SUFFIX;
-
- boolean flag = OssUtils.uploadFileWithBase64(uploadDto.base64Str, imageName);
- if (flag) {
- String url = aliOssProperties.getBucketName() + "/" + imageName;
- return Result.ok(MessageSourceUtils.getString("result_success_msg"), url);
- }
- return Result.fail(MessageSourceUtils.getString("uploadFile_controller_0001"));
- }
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/controller/LoginController.java b/src/main/java/com/xcong/excoin/common/system/controller/LoginController.java
deleted file mode 100644
index 4754bb5..0000000
--- a/src/main/java/com/xcong/excoin/common/system/controller/LoginController.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.xcong.excoin.common.system.controller;
-
-import cn.hutool.core.codec.Base64;
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
-import cn.hutool.crypto.asymmetric.Sign;
-import cn.hutool.crypto.asymmetric.SignAlgorithm;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.annotations.SubmitRepeat;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.bean.LoginUserBean;
-import com.xcong.excoin.common.system.dto.LoginDto;
-import com.xcong.excoin.common.system.dto.RegisterDto;
-import com.xcong.excoin.configurations.properties.ApplicationProperties;
-import com.xcong.excoin.configurations.properties.SecurityProperties;
-import com.xcong.excoin.modules.member.service.MemberService;
-import com.xcong.excoin.utils.RedisUtils;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.core.Authentication;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @Author wzy
- * @Date 2020/5/11
- * @email wangdoubleone@gmail.com
- * @Version V1.0
- **/
-@Slf4j
-@Api(value = "登陆注册类", tags = "登陆注册类")
-@RestController
-@RequestMapping(value = "/")
-public class LoginController {
-
- @Resource
- private MemberService memberservice;
-
- @Resource
- private ApplicationProperties applicationProperties;
-
- @Resource
- private SecurityProperties securityProperties;
-
- @Resource
- private AuthenticationManagerBuilder authenticationManagerBuilder;
-
- @Resource
- private RedisUtils redisUtils;
-
- @ApiOperation(value = "登陆接口", notes = "登陆接口")
- @PostMapping("/login")
- public Result login(@RequestBody @Validated LoginDto loginDto, HttpServletRequest request) {
- // 将账号密码交给spring security验证,并调用userServiceDetails
- UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), SecureUtil.md5(loginDto.getPassword()));
- Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authToken);
-
- // 获取当前验证过后的用户
- LoginUserBean loginUserBean = (LoginUserBean) authentication.getPrincipal();
-
- // 生成UUID作为token
- String token = IdUtil.simpleUUID();
- String redisToken = "";
- String redisMember = "";
- if (LoginUserUtils.isBrowser(request)) {
- redisToken = AppContants.PC_LOGIN_PREFIX + token;
- redisMember = AppContants.PC_LOGIN_PREFIX + loginUserBean.getMemberEntity().getId();
- } else {
- redisToken = AppContants.APP_LOGIN_PREFIX + token;
- redisMember = AppContants.APP_LOGIN_PREFIX + loginUserBean.getMemberEntity().getId();
- }
-
- if (StrUtil.isNotBlank(redisUtils.getString(redisMember))) {
- if (redisMember.contains(AppContants.APP_LOGIN_PREFIX)) {
- redisUtils.del(AppContants.APP_LOGIN_PREFIX + redisUtils.getString(redisMember));
- } else {
- redisUtils.del(AppContants.PC_LOGIN_PREFIX + redisUtils.getString(redisMember));
- }
- }
- redisUtils.set(redisToken, JSONObject.toJSONString(loginUserBean.getMemberEntity()), applicationProperties.getRedisExpire());
- redisUtils.set(redisMember, token);
- Map<String, Object> authInfo = new HashMap<>();
- // 开启debug模式,则将加密后的token返回
- if (applicationProperties.isDebug()) {
- authInfo.put("token", token);
- authInfo.put("rsaToken", AppContants.TOKEN_START_WITH + generateAsaToken(token));
- authInfo.put("user", loginUserBean);
- } else {
- authInfo.put("token", token);
- authInfo.put("user", loginUserBean);
- }
- return Result.ok("success", authInfo);
- }
-
- public String generateAsaToken(String token) {
- RSA rsa = new RSA(null, securityProperties.getPublicKey());
- return rsa.encryptBase64(token + "_" + System.currentTimeMillis(), KeyType.PublicKey);
- }
-
- @SubmitRepeat
- @ApiOperation(value = "app注册接口", notes = "app注册接口,验证码必须输入可默认为123456")
- @PostMapping(value = "/register")
- public Result register(@RequestBody @Validated RegisterDto registerDto) {
- return memberservice.register(registerDto);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/dto/Base64UploadDto.java b/src/main/java/com/xcong/excoin/common/system/dto/Base64UploadDto.java
deleted file mode 100644
index c4fa5f0..0000000
--- a/src/main/java/com/xcong/excoin/common/system/dto/Base64UploadDto.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xcong.excoin.common.system.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * @author wzy
- * @date 2020-05-29
- **/
-@Data
-@ApiModel(value = "Base64UploadDto", description = "base64文件上传参数类")
-public class Base64UploadDto {
-
- @NotBlank
- @ApiModelProperty(value = "base64字符串")
- public String base64Str;
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java b/src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java
deleted file mode 100644
index 1721f62..0000000
--- a/src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.common.system.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * @author wzy
- * @date 2020-05-12
- **/
-@Data
-@ApiModel(value = "登陆接口接收类", description = "登陆接口接收类")
-public class LoginDto {
-
-
- @ApiModelProperty(value = "用户名", example = "11111")
- @NotBlank(message = "用户名或密码错误")
- private String username;
-
- @ApiModelProperty(value = "密码", example = "123456")
- @NotBlank(message = "用户名或密码错误")
- private String password;
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/dto/RegisterDto.java b/src/main/java/com/xcong/excoin/common/system/dto/RegisterDto.java
deleted file mode 100644
index 188904d..0000000
--- a/src/main/java/com/xcong/excoin/common/system/dto/RegisterDto.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin.common.system.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.Length;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-
-/**
- * 注册用户接收类
- *
- * @author wzy
- * @date 2020-05-18
- **/
-@Data
-@ApiModel(value = "注册接口参数类", description = "注册接口参数类")
-public class RegisterDto {
-
- @ApiModelProperty(value = "账号", example = "13412341234")
- @NotBlank(message = "账号不能为空")
- private String account;
-
- @ApiModelProperty(value = "密码", example = "123456")
- @NotBlank(message = "密码不能为空")
- private String password;
-
- @ApiModelProperty(value = "账号类型 1-手机 2-邮箱", example = "1")
- @NotNull(message = "账号类型不能为空")
- private Integer type;
-
- @ApiModelProperty(value = "验证码", example = "123456")
- @NotBlank(message = "验证码不能为空")
- private String code;
-
- @ApiModelProperty(value = "推荐人id", example = "rxadr3")
- private String refererId;
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/mapper/CandlestickMapper.java b/src/main/java/com/xcong/excoin/common/system/mapper/CandlestickMapper.java
deleted file mode 100644
index 4e6fca1..0000000
--- a/src/main/java/com/xcong/excoin/common/system/mapper/CandlestickMapper.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.common.system.mapper;
-
-import com.huobi.client.model.Candlestick;
-import com.xcong.excoin.modules.symbols.parameter.vo.KlineDataVo;
-import com.xcong.excoin.utils.api.response.KlineReturn;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.factory.Mappers;
-
-/**
- * @author wzy
- * @date 2020-05-29
- **/
-@Mapper
-public abstract class CandlestickMapper {
- public static final CandlestickMapper INSTANCE = Mappers.getMapper(CandlestickMapper.class);
-
- @Mapping(source = "timestamp", target = "time")
- public abstract KlineDataVo toKlineDataVo(Candlestick candlestick);
-
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/service/CommonService.java b/src/main/java/com/xcong/excoin/common/system/service/CommonService.java
deleted file mode 100644
index 444fc77..0000000
--- a/src/main/java/com/xcong/excoin/common/system/service/CommonService.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.xcong.excoin.common.system.service;
-
-
-/**
- * @author helius
- */
-public interface CommonService {
-
- public boolean verifyCode(String account, String code);
-
- public String generateOrderNo(Long mid);
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java b/src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java
deleted file mode 100644
index d08afa0..0000000
--- a/src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.xcong.excoin.common.system.service;
-
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.asymmetric.Sign;
-import cn.hutool.crypto.asymmetric.SignAlgorithm;
-import com.xcong.excoin.common.exception.GlobalException;
-import com.xcong.excoin.common.system.bean.LoginUserBean;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @Author wzy
- * @Date 2020/5/11
- * @email wangdoubleone@gmail.com
- * @Version V1.0
- **/
-@Slf4j
-@Service("userDetailsService")
-public class UserDetailsServiceImpl implements UserDetailsService {
-
- @Resource
- private MemberDao memberDao;
-
- @Override
- public LoginUserBean loadUserByUsername(String username) throws UsernameNotFoundException {
- log.info("#登陆账号:{}#", username);
- List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
-// GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
-// grantedAuthorities.add(grantedAuthority);
-
- MemberEntity memberEntity = memberDao.selectMemberInfoByAccount(username);
- if (memberEntity != null) {
- memberEntity.setPassword(new BCryptPasswordEncoder().encode(memberEntity.getPassword()));
- } else {
- throw new UsernameNotFoundException("");
- }
-
- if (MemberEntity.ACCOUNT_STATUS_DISABLED == memberEntity.getAccountStatus()) {
- throw new GlobalException(MessageSourceUtils.getString("member_service_0092"));
- }
-
- return new LoginUserBean(memberEntity, null, null);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/common/system/service/impl/CommonServiceImpl.java b/src/main/java/com/xcong/excoin/common/system/service/impl/CommonServiceImpl.java
deleted file mode 100644
index 265b41a..0000000
--- a/src/main/java/com/xcong/excoin/common/system/service/impl/CommonServiceImpl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.xcong.excoin.common.system.service.impl;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.RandomUtil;
-import cn.hutool.core.util.StrUtil;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.system.service.CommonService;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.Date;
-
-/**
- * @author wzy
- * @date 2020-05-29
- **/
-@Slf4j
-@Service
-public class CommonServiceImpl implements CommonService {
-
- @Resource
- private RedisUtils redisUtils;
-
- @Override
- public boolean verifyCode(String account, String code) {
- String cacheCode = redisUtils.getString(AppContants.VERIFY_CODE_PREFIX + account);
- if (StrUtil.isBlank(cacheCode)) {
- return false;
- }
- if (code.equals(cacheCode)) {
- redisUtils.del(AppContants.VERIFY_CODE_PREFIX + account);
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public String generateOrderNo(Long mid) {
- StringBuilder orderNo = new StringBuilder();
- String date = DateUtil.format(new Date(), "yyyyMMdd");
- orderNo.append(date);
- orderNo.append(mid);
- orderNo.append(RandomUtil.randomNumbers(2));
-
- Object countObj = redisUtils.get(date);
- if (countObj == null) {
- countObj = 0;
- }
- int count = (int) countObj;
- count++;
- redisUtils.set(date, count, 24 * 60 * 60);
-
- int size = 4;
- for (int i = 0; i < size - String.valueOf(count).length(); i++) {
- orderNo.append("0");
- }
- orderNo.append(count);
- return orderNo.toString();
- }
-}
diff --git a/src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java b/src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java
deleted file mode 100644
index 1b79633..0000000
--- a/src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.xcong.excoin.configurations;
-
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import io.swagger.annotations.Api;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-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 java.util.ArrayList;
-import java.util.List;
-
-/**
- * @Author wzy
- * @Date 2020/5/11
- * @email wangdoubleone@gmail.com
- * @Version V1.0
- **/
-@Configuration
-@EnableSwagger2
-public class SwaggerConfig {
-
- @Bean
- public Docket createRestApi(){
- // 添加请求参数,我们这里把token作为请求头部参数传入后端
- ParameterBuilder parameterBuilder = new ParameterBuilder();
- List<Parameter> parameters = new ArrayList<Parameter>();
- parameterBuilder.name("Authorization").description("令牌").modelRef(new ModelRef("string")).parameterType("header")
- .required(false).build();
- parameters.add(parameterBuilder.build());
- return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
- .paths(PathSelectors.any()).build().globalOperationParameters(parameters).ignoredParameterTypes(MemberEntity.class);
- }
-
- private ApiInfo apiInfo(){
- return new ApiInfoBuilder()
- .title("ExCoin")
- .description("This is a restful api document of ExCoin.")
- .version("1.0")
- .build();
- }
-}
diff --git a/src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java b/src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java
index 06994e0..dd6595f 100644
--- a/src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java
+++ b/src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java
@@ -1,16 +1,10 @@
package com.xcong.excoin.configurations;
-import com.aliyun.oss.OSS;
-import com.aliyun.oss.OSSClientBuilder;
import com.xcong.excoin.configurations.properties.AliOssProperties;
-import com.xcong.excoin.configurations.security.UserAuthenticationArgumentResolver;
-import com.xcong.excoin.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringBootConfiguration;
-import org.springframework.context.annotation.Bean;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@@ -30,7 +24,6 @@
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
- resolvers.add(new UserAuthenticationArgumentResolver());
}
/**
@@ -46,13 +39,4 @@
.allowCredentials(true).maxAge(3600);
}
- @Bean
- public OSS ossClient() {
- return new OSSClientBuilder().build(aliOssProperties.getEndPoint(), aliOssProperties.getAccessKeyId(), aliOssProperties.getAccessKeySecret());
- }
-
-// @Bean
-// public SpringContextHolder springContextHolder() {
-// return new SpringContextHolder();
-// }
}
diff --git a/src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java b/src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java
index 5e69b7a..46aad94 100644
--- a/src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java
+++ b/src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java
@@ -1,9 +1,5 @@
package com.xcong.excoin.configurations.interceptor;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
@@ -34,30 +30,6 @@
return invocation.proceed();
}
- if (SqlCommandType.INSERT == sqlCommandType) {
- if (parameter instanceof DefaultSqlSession.StrictMap) {
- Map map = (Map) parameter;
- List list = (List) map.get("list");
- for (Object o : list) {
- injectForInsert(o);
- }
- } else {
- injectForInsert(parameter);
- }
- }
-
- if (SqlCommandType.UPDATE == sqlCommandType) {
- if (parameter instanceof DefaultSqlSession.StrictMap) {
- Map map = (Map) parameter;
- List list = (List) map.get("list");
- for (Object o : list) {
- injectForUpdate(o);
- }
- } else {
- injectForUpdate(parameter);
- }
- }
-
return invocation.proceed();
}
@@ -71,34 +43,4 @@
}
- public void injectForInsert(Object o) {
- MemberEntity member = LoginUserUtils.getUser();
- if (o instanceof BaseEntity) {
- BaseEntity baseEntity = (BaseEntity) o;
- if (member != null) {
- String by = member.getPhone() != null ? member.getPhone() : member.getEmail();
- baseEntity.setCreateBy(by);
- baseEntity.setUpdateBy(by);
- } else {
- baseEntity.setCreateBy(AppContants.SYSTEM_USER);
- baseEntity.setUpdateBy(AppContants.SYSTEM_USER);
- }
- baseEntity.setCreateTime(new Date());
- baseEntity.setUpdateTime(new Date());
- }
- }
-
- public void injectForUpdate(Object o) {
- MemberEntity member = LoginUserUtils.getUser();
- if (o instanceof BaseEntity) {
- BaseEntity baseEntity = (BaseEntity) o;
- if (member != null) {
- String by = member.getPhone() != null ? member.getPhone() : member.getEmail();
- baseEntity.setUpdateBy(by);
- } else {
- baseEntity.setUpdateBy(AppContants.SYSTEM_USER);
- }
- baseEntity.setUpdateTime(new Date());
- }
- }
}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java b/src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java
deleted file mode 100644
index a998762..0000000
--- a/src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.configurations.security;
-
-import lombok.RequiredArgsConstructor;
-import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.web.DefaultSecurityFilterChain;
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-
-/**
- * @author wzy
- * @date 2020-05-12
- **/
-@RequiredArgsConstructor
-public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
-
- @Override
- public void configure(HttpSecurity http) {
- TokenFilter customFilter = new TokenFilter();
- http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java b/src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java
deleted file mode 100644
index 362eb8b..0000000
--- a/src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.xcong.excoin.configurations.security;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
-import com.alibaba.fastjson.JSONObject;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.exception.GlobalException;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.bean.LoginUserBean;
-import com.xcong.excoin.configurations.properties.ApplicationProperties;
-import com.xcong.excoin.configurations.properties.SecurityProperties;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.utils.RedisUtils;
-import com.xcong.excoin.utils.SpringContextHolder;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.util.StringUtils;
-import org.springframework.web.filter.GenericFilterBean;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * @author wzy
- * @date 2020-05-12
- **/
-@Slf4j
-public class TokenFilter extends GenericFilterBean {
-
- private final ApplicationProperties applicationProperties = SpringContextHolder.getBean(ApplicationProperties.class);
-
- private final SecurityProperties securityProperties = SpringContextHolder.getBean(SecurityProperties.class);
-
- private final RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
-
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) servletRequest;
- HttpServletResponse response = (HttpServletResponse) servletResponse;
- String token = resolveToken(request);
-
- if (!AppContants.TIME_OUT.equals(token)) {
- if (StrUtil.isNotBlank(token)) {
- String redisKey = "";
- // 根据user-agent判断pc端还是app端
- if (LoginUserUtils.isBrowser(request)) {
- redisKey = AppContants.PC_LOGIN_PREFIX + token;
- } else {
- redisKey = AppContants.APP_LOGIN_PREFIX + token;
- }
-
- String loginStr = (String) redisUtils.get(redisKey);
- if (StrUtil.isNotBlank(loginStr)) {
- MemberEntity loginUser = JSONObject.parseObject(loginStr, MemberEntity.class);
- Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser, token, new ArrayList<>());
- SecurityContextHolder.getContext().setAuthentication(authentication);
- redisUtils.expire(redisKey, 36000);
- } else {
- log.info("token无法查询:{}", token);
- SecurityContextHolder.clearContext();
- }
- } else {
-// log.info("token为空:{}", request.getRequestURI());
- SecurityContextHolder.clearContext();
- }
- } else {
- response.setHeader("TimeOut", AppContants.TIME_OUT);
- SecurityContextHolder.clearContext();
- }
- filterChain.doFilter(servletRequest, servletResponse);
- }
-
- /**
- * 解析前端传来的token,先去掉Bearer,在rsa解密得到token_time,返回token,并判断time与当前是否在5s内
- *
- * @param request
- * @return
- */
- private String resolveToken(HttpServletRequest request) {
- try {
- String bearerToken = request.getHeader(AppContants.TOKEN_HEADER);
- if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(AppContants.TOKEN_START_WITH)) {
- // 去掉令牌前缀
- String rsaToken = bearerToken.replace(AppContants.TOKEN_START_WITH, "");
- RSA rsa = new RSA(securityProperties.getPrivateKey(), null);
- String[] tokens = StrUtil.split(rsa.decryptStr(rsaToken, KeyType.PrivateKey), "_");
-
- if (verifyTokenExpired(Long.parseLong(tokens[1]))) {
- return tokens[0];
- } else {
-// log.info("前面token为{}", tokens[0]);
-// log.info("时间为:{}, 当前时间为:{}", tokens[1], System.currentTimeMillis());
- return AppContants.TIME_OUT;
- }
- }
-// log.info("bearerToken---->{}", bearerToken);
- } catch (Exception e) {
- log.error("#解析token异常#", e);
- return null;
- }
- return null;
- }
-
- private Boolean verifyTokenExpired(Long time) {
- boolean isDebug = applicationProperties.isDebug();
- if (!isDebug) {
- long currentTime = System.currentTimeMillis();
- return currentTime - time <= 10000;
- }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/UserAuthenticationArgumentResolver.java b/src/main/java/com/xcong/excoin/configurations/security/UserAuthenticationArgumentResolver.java
deleted file mode 100644
index 5dee717..0000000
--- a/src/main/java/com/xcong/excoin/configurations/security/UserAuthenticationArgumentResolver.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin.configurations.security;
-
-import com.xcong.excoin.common.annotations.UserAuth;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import org.springframework.core.MethodParameter;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.web.bind.support.WebDataBinderFactory;
-import org.springframework.web.context.request.NativeWebRequest;
-import org.springframework.web.method.support.HandlerMethodArgumentResolver;
-import org.springframework.web.method.support.ModelAndViewContainer;
-
-/**
- * 自动注入登陆用户
- *
- * @author wzy
- * @date 2020-05-13
- **/
-public class UserAuthenticationArgumentResolver implements HandlerMethodArgumentResolver {
-
- @Override
- public boolean supportsParameter(MethodParameter parameter) {
- return parameter.getParameterAnnotation(UserAuth.class) != null && parameter.getParameterType().equals(MemberEntity.class);
- }
-
- @Override
- public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
- Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
- if (authentication == null) {
- return null;
- }
-
- MemberEntity auth = null;
- if (authentication.getPrincipal() != null) {
- auth = (MemberEntity) authentication.getPrincipal();
- }
- return auth;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java b/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
index dfe6523..8aa5e43 100644
--- a/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
+++ b/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
@@ -53,8 +53,7 @@
.antMatchers("/api/member/getAppVersionInfo").permitAll()
.antMatchers("/api/orderCoin/searchSymbolResultList").permitAll()
.antMatchers("/api/orderCoin/findCollect").permitAll()
- .anyRequest().authenticated()
- .and().apply(securityConfiguereAdapter());
+ .anyRequest().authenticated();
}
@Override
@@ -77,7 +76,4 @@
return new CustomAuthenticationEntryPoint();
}
- public TokenConfigurer securityConfiguereAdapter() {
- return new TokenConfigurer();
- }
}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/controller/BlockController.java b/src/main/java/com/xcong/excoin/modules/blackchain/controller/BlockController.java
deleted file mode 100644
index e024e8d..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/controller/BlockController.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.xcong.excoin.modules.blackchain.controller;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestHeader;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.blackchain.service.BlockSerive;
-import com.xcong.excoin.utils.RedisUtils;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-import io.swagger.annotations.ApiOperation;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@Api(value = "链上钱包接口", tags = "链上钱包接口")
-@RestController
-@RequestMapping(value = "/api/block")
-public class BlockController {
-
-
-
- @Autowired
- RedisUtils redisUtils;
- @Autowired
- BlockSerive blockSerive;
- /**
- * BTC
- * @param token
- * @return
- */
- @ApiOperation(value = "链上生成钱包地址接口", notes = "链上生成钱包地址接口")
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query")
- })
- @GetMapping(value = "/findBlockAddress")
- public Result findBlockAddress(String symbol) {
- return blockSerive.findBlockAddress(symbol);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/model/EosResult.java b/src/main/java/com/xcong/excoin/modules/blackchain/model/EosResult.java
deleted file mode 100644
index ca0bd19..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/model/EosResult.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.blackchain.model;
-
-import lombok.Data;
-
-/**
- * 数据样例
- * EosResult(quantity=2.0000 EOS, memo=aa, from=okbtothemoon, to=biueeostoken, accountActionSeq=2)
- */
-@Data
-public class EosResult {
- /**
- * 转账数量
- */
- private String quantity;
-
- /**
- * 转账标记
- */
- private String memo;
- private String from;
- private String to;
-
- /**
- * 这笔转账对应于这个账户的序号
- */
- private Integer accountActionSeq;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTransResult.java b/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTransResult.java
deleted file mode 100644
index a9bf035..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTransResult.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.xcong.excoin.modules.blackchain.model;
-
-import java.util.List;
-
-// https://github.com/ripple/rippled-historical-database#get-account-transaction-history
-public class XrpTransResult {
- private String result; //success
- private Integer count; //
- private String marker;//
-
- //transactions
- List<XrpTransactions> transactions;
-
- public String getResult() {
- return result;
- }
-
- public void setResult(String result) {
- this.result = result;
- }
-
- public Integer getCount() {
- return count;
- }
-
- public void setCount(Integer count) {
- this.count = count;
- }
-
- public String getMarker() {
- return marker;
- }
-
- public void setMarker(String marker) {
- this.marker = marker;
- }
-
- public List<XrpTransactions> getTransactions() {
- return transactions;
- }
-
- public void setTransactions(List<XrpTransactions> transactions) {
- this.transactions = transactions;
- }
-
-
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTransactions.java b/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTransactions.java
deleted file mode 100644
index f69f00f..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTransactions.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xcong.excoin.modules.blackchain.model;
-
-public class XrpTransactions {
-
- private String hash;
- private Integer ledger_index;
- private String date;//2019-10-28T15:01:01+00:00
- private XrpTx tx;
-
- public String getHash() {
- return hash;
- }
- public void setHash(String hash) {
- this.hash = hash;
- }
- public Integer getLedger_index() {
- return ledger_index;
- }
- public void setLedger_index(Integer ledger_index) {
- this.ledger_index = ledger_index;
- }
- public String getDate() {
- return date;
- }
- public void setDate(String date) {
- this.date = date;
- }
- public XrpTx getTx() {
- return tx;
- }
- public void setTx(XrpTx tx) {
- this.tx = tx;
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTx.java b/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTx.java
deleted file mode 100644
index 9b7a883..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/model/XrpTx.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xcong.excoin.modules.blackchain.model;
-
-import lombok.Data;
-
-@Data
-public class XrpTx {
- private String transactionType;
- private Integer flags;
- private Integer sequence;
- private Integer destinationTag; // 对应的用户标签
- private Integer amount; // 金额 除以1000000 一百万
- private Integer fee; // 手续费
- private String account; // 转账人
- private String destination; // 收款人(收款人是系统账户 说明是转入)
-
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/BchService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/BchService.java
deleted file mode 100644
index eb142df..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/BchService.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang3.StringUtils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-
-
-public class BchService {
-
-
- private static BchService service = null;
- private final static String RESULT = "result";
- private final static String METHOD_SEND_TO_ADDRESS = "sendtoaddress";
- private final static String METHOD_GET_TRANSACTION = "gettransaction";
- private final static String METHOD_LIST_TRANSACTIONS = "listtransactions";
- private final static String METHOD_GET_BLOCK_COUNT = "getblockcount";
- private final static String METHOD_NEW_ADDRESS = "getnewaddress";
- private final static String METHOD_GET_BALANCE = "getbalance";
- private final static String METHOD_GET_BALANCE_ADDRESS = "getreceivedbyaddress";
- private final static String METHOD_WALLET_PASSPHRASE = "walletpassphrase";
- private final static String METHOD_WALLET_LOCK = "walletlock";
-
- private String url = "http://121.40.86.163:1882";
- private String username = "biyi";
- private String password = "biyi12345";
-
- public static BchService getInstance() {
- if (service != null) {
- return service;
- }
- return new BchService();
- }
-
- private BchService() {
- }
-
- /**
- * 创建BTC钱包 每个账户对应一个地址 方便后续操作
- * @param mId 账户
- * @return
- */
- public static Map<String, String> createWallet(String mId) {
- BchService btcService = getInstance();
- // 创建钱包地址
- String address = btcService.getAddress(mId);
- // 私钥
- String privateKey = btcService.dumpprivkey(address);
- Map<String, String> result = new HashMap<String,String>();
- result.put("address", address);
- result.put("privateKey", privateKey);
- return result;
- }
- public String getAddress(String label) {
- try {
- JSONObject json = doRequest(METHOD_NEW_ADDRESS,label);
- if (isError(json)) {
- return "";
- }
- return json.getString(RESULT);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- private JSONObject doRequest(String method, Object... params) {
- JSONObject param = new JSONObject();
- param.put("id", System.currentTimeMillis() + "");
- param.put("jsonrpc", "2.0");
- param.put("method", method);
- if (params != null) {
- param.put("params", params);
- }
- String creb = Base64.encodeBase64String((username + ":" + password).getBytes());
- Map<String, String> headers = new HashMap<>(2);
- headers.put("Authorization", "Basic " + creb);
- return JSON.parseObject(HttpUtil.jsonPost(url, headers, param.toJSONString()));
- }
-
- private boolean isError(JSONObject json) {
- if (json == null || (StringUtils.isNotEmpty(json.getString("error")) && json.get("error") != "null")) {
- return true;
- }
- return false;
- }
-
- public String dumpprivkey(String address) {
- try {
- JSONObject obj = doRequest("dumpprivkey", address);
- System.out.println(obj);
- if (!isError(obj)) {
- return obj.getString(RESULT);
- } else {
- return null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 查询给定地址的总收款额(只计算接受的)
- * @param address
- * @return
- */
- public BigDecimal getBalance(String address) {
- JSONObject json = doRequest(METHOD_GET_BALANCE_ADDRESS,address,3);
- if (!isError(json)) {
- return new BigDecimal(json.getString(RESULT));
- } else {
- return null;
- }
- }
-
- public String METHOD_GET_BLOCK_COUNT() {
- JSONObject json = doRequest(METHOD_GET_BLOCK_COUNT);
- if (!isError(json)) {
- return json.getString(RESULT);
- } else {
- return null;
- }
- }
- public static void main(String[] args) {
- BchService ser = new BchService();
- //ser.getBalance("36RiLqCrnFfBoyUUHpGvEotXiMRtrJG8dp");
- //System.out.println(ser.METHOD_GET_BLOCK_COUNT());
- System.out.println(ser.getBalance("36RiLqCrnFfBoyUUHpGvEotXiMRtrJG8dp"));
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/BigDecimalUtil.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/BigDecimalUtil.java
deleted file mode 100644
index 3043a0f..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/BigDecimalUtil.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.text.DecimalFormat;
-
-/**
- * 数据计算工具类
- *
- * @author cloud cloud
- * @create 2017/10/11
- **/
-public class BigDecimalUtil {
-
-
- /**
- * 基本单位
- */
- private static final BigDecimal UNIT = new BigDecimal(100000000);
-
- /**
- * 对double数据进行取精度.
- * @param value double数据.
- * @param scale 精度位数(保留的小数位数).
- * @param roundingMode 精度取值方式.
- * @return 精度计算后的数据.
- */
- public static double round(double value, int scale,
- int roundingMode) {
- BigDecimal bd = new BigDecimal(value);
- bd = bd.setScale(scale, roundingMode);
- double d = bd.doubleValue();
- bd = null;
- return d;
- }
-
- /**
- * 获取四位小数的字符串,小数位不够补充0
- * @param value
- * @return X.0000
- */
- public static String getFourString(double value){
- DecimalFormat df = new DecimalFormat("0.0000");
- return df.format(value);
- }
-
-
- /**
- * double 相加
- * @param d1
- * @param d2
- * @return
- */
- public static double sum(Double d1,Double d2){
- BigDecimal bd1 = new BigDecimal(d1.toString());
- BigDecimal bd2 = new BigDecimal(d2.toString());
- return bd1.add(bd2).doubleValue();
- }
-
- public static double sum(String a,String b){
- BigDecimal pa = new BigDecimal(a);
- BigDecimal pb = new BigDecimal(b);
- return pa.add(pb).doubleValue();
- }
-
-
- /**
- * double 相减
- * @param d1
- * @param d2
- * @return
- */
- public static double sub(double d1,double d2){
- BigDecimal bd1 = new BigDecimal(Double.toString(d1));
- BigDecimal bd2 = new BigDecimal(Double.toString(d2));
- return bd1.subtract(bd2).setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();
- }
-
- /**
- * double 乘法
- * @param d1
- * @param d2
- * @return
- */
- public static double mul(double d1,double d2){
- BigDecimal bd1 = new BigDecimal(Double.toString(d1));
- BigDecimal bd2 = new BigDecimal(Double.toString(d2));
- return bd1.multiply(bd2).setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();
- }
-
-
- /**
- * double 除法
- * @param d1
- * @param d2
- * @param scale 四舍五入 小数点位数
- * @return
- */
- public static double div(double d1,double d2,int scale){
- // 当然在此之前,你要判断分母是否为0,
- // 为0你可以根据实际需求做相应的处理
-
- BigDecimal bd1 = new BigDecimal(Double.toString(d1));
- BigDecimal bd2 = new BigDecimal(Double.toString(d2));
- return bd1.divide
- (bd2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
- }
-
- /**
- * 长整数相乘
- * @param pa
- * @param pb
- * @return
- */
- public static long longMul(long pa,long pb){
- BigDecimal b1 = new BigDecimal(pa);
- BigDecimal b2 = new BigDecimal(pb);
- return b1.multiply(b2).longValue();
- }
-
- public static long longMul(long pa ,Double rate){
- BigDecimal b1 = new BigDecimal(pa);
- BigDecimal b2 = new BigDecimal(rate.toString());
- b2 = b2.setScale(6,BigDecimal.ROUND_HALF_UP);
- return b1.multiply(b2).longValue();
- }
-
- public static long longMul(long pa ,String rate){
- BigDecimal b1 = new BigDecimal(pa);
- BigDecimal b2 = new BigDecimal(rate);
- return b1.multiply(b2).longValue();
- }
-
- /**
- * 长整数相减
- * @param pa
- * @param pb
- * @return
- */
- public static long longSub(long pa,long pb){
- BigDecimal b1 = new BigDecimal(pa);
- BigDecimal b2 = new BigDecimal(pb);
- return b1.subtract(b2).longValue();
- }
-
- /**
- * 长整数相加
- * @param pa
- * @param pb
- * @return
- */
- public static long longAdd(long pa,long pb){
- BigDecimal b1 = new BigDecimal(pa);
- BigDecimal b2 = new BigDecimal(pb);
- return b1.add(b2).longValue();
- }
-
- /**
- * 入参转化
- * @param value
- * @return
- */
- public static long inputConvert(Double value){
- BigDecimal input = new BigDecimal(value.toString());
- return input.multiply(UNIT).longValue();
- }
-
- /**
- * 输出转化
- * @param value
- * @return
- */
- public static double outputConvert(long value){
- BigDecimal output = new BigDecimal(value);
- return output.divide(UNIT,6, RoundingMode.DOWN).doubleValue();
- }
-
- public static void main(String[] args) {
- long res = longMul(100000000,0.000009999999);
- System.out.println(res);
-
- }
-
- public static long sum(Long d1,String d2){
- BigDecimal bd1 = new BigDecimal(d1.toString());
- BigDecimal bd2 = new BigDecimal(d2);
- return bd1.add(bd2).longValue();
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/BlockSerive.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/BlockSerive.java
deleted file mode 100644
index 4784320..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/BlockSerive.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import com.xcong.excoin.common.response.Result;
-
-public interface BlockSerive {
-
- Result findBlockAddress(String symbol);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/BtcService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/BtcService.java
deleted file mode 100644
index b8a4c84..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/BtcService.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang3.StringUtils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-
-
-public class BtcService {
-
-
- private static BtcService service = null;
- private final static String RESULT = "result";
- private final static String METHOD_SEND_TO_ADDRESS = "sendtoaddress";
- private final static String METHOD_GET_TRANSACTION = "gettransaction";
- private final static String METHOD_LIST_TRANSACTIONS = "listtransactions";
- private final static String METHOD_GET_BLOCK_COUNT = "getblockcount";
- private final static String METHOD_NEW_ADDRESS = "getnewaddress";
- private final static String METHOD_GET_BALANCE = "getbalance";
- private final static String METHOD_GET_BALANCE_ADDRESS = "getreceivedbyaddress";
- private final static String METHOD_WALLET_PASSPHRASE = "walletpassphrase";
- private final static String METHOD_WALLET_LOCK = "walletlock";
-
- private String url = "http://120.55.86.146:1880";
- private String username = "biyi";
- private String password = "biyi1234";
-
- public static BtcService getInstance() {
- if (service != null) {
- return service;
- }
- return new BtcService();
- }
-
- private BtcService() {
- }
-
- /**
- * 创建BTC钱包 每个账户对应一个地址 方便后续操作
- * @param mId 账户
- * @return
- */
- public static Map<String, String> createWallet(String mId) {
- BtcService btcService = getInstance();
- // 创建钱包地址
- String address = btcService.getAddress(mId);
- // 私钥
- String privateKey = btcService.dumpprivkey(address);
- Map<String, String> result = new HashMap<String,String>();
- result.put("address", address);
- result.put("privateKey", privateKey);
- return result;
- }
- public String getAddress(String label) {
- try {
- JSONObject json = doRequest(METHOD_NEW_ADDRESS,label);
- if (isError(json)) {
- return "";
- }
- return json.getString(RESULT);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- private JSONObject doRequest(String method, Object... params) {
- JSONObject param = new JSONObject();
- param.put("id", System.currentTimeMillis() + "");
- param.put("jsonrpc", "2.0");
- param.put("method", method);
- if (params != null) {
- param.put("params", params);
- }
- String creb = Base64.encodeBase64String((username + ":" + password).getBytes());
- Map<String, String> headers = new HashMap<>(2);
- headers.put("Authorization", "Basic " + creb);
- return JSON.parseObject(HttpUtil.jsonPost(url, headers, param.toJSONString()));
- }
-
- private boolean isError(JSONObject json) {
- if (json == null || (StringUtils.isNotEmpty(json.getString("error")) && json.get("error") != "null")) {
- return true;
- }
- return false;
- }
-
- public String dumpprivkey(String address) {
- try {
- JSONObject obj = doRequest("dumpprivkey", address);
- System.out.println(obj);
- if (!isError(obj)) {
- return obj.getString(RESULT);
- } else {
- return null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 查询给定地址的总收款额(只计算接受的)
- * @param address
- * @return
- */
- public BigDecimal getBalance(String address) {
- JSONObject json = doRequest(METHOD_GET_BALANCE_ADDRESS,address,3);
- if (!isError(json)) {
- return new BigDecimal(json.getString(RESULT));
- } else {
- return null;
- }
- }
-
- public String METHOD_GET_BLOCK_COUNT() {
- JSONObject json = doRequest(METHOD_GET_BLOCK_COUNT);
- if (!isError(json)) {
- return json.getString(RESULT);
- } else {
- return null;
- }
- }
- public static void main(String[] args) {
- BtcService ser = new BtcService();
- //ser.getBalance("36RiLqCrnFfBoyUUHpGvEotXiMRtrJG8dp");
- //System.out.println(ser.METHOD_GET_BLOCK_COUNT());
- System.out.println(ser.getBalance("36RiLqCrnFfBoyUUHpGvEotXiMRtrJG8dp"));
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/DateUtil.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/DateUtil.java
deleted file mode 100644
index d8217db..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/DateUtil.java
+++ /dev/null
@@ -1,1369 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-import java.sql.Timestamp;
-import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.ParseException;
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.lang.StringUtils;
-public class DateUtil {
-
- public DateUtil() {
-
- }
- /**
- * 测试用
- * @param args
- * @throws ParseException
- */
- public static void main(String[] args) throws ParseException {
-// long time = System.currentTimeMillis()+7200000;
-// Date a = new Date(time);
-// long space = dateSpaceHours(new Date(), a);
-// System.out.println(space);
-// System.out.println(DateUtil.dateToString(DateUtil.getStringToDate(DateUtil.getSQLDateYMD())));
-
-// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
-// Date date= DateUtil.addDays(new Date(), -1);
-// System.out.println(date);
-// System.out.println(DateUtil.dateToString(date));
-// System.out.println(simpleDateFormat.format(date));
-// System.out.println(DateUtil.getStringToDate(dateToStringYMD(date),"yyyy-MM-dd"));
-// System.out.println(DateUtil.getStringToDate(null));
- //for(int i=0;i<10;i++){
- //System.out.println(getSQLDateYMD());
- //}
- //System.out.println(dateDiff("2013-06-08 12:25:23","2013-07-08 12:25:23"));
- // System.out.println(currentTimeDiff2("2013-12-08"));
- // System.out.println(compare_date("2013-07-08 12:25:23", "2013-07-08 12:23:23"));
- //System.out.println(fomatDate("2013-10-16 9:27:34"));
- //System.out.println(System.currentTimeMillis());
- //System.out.println(getTenTimestamp());
- //System.out.println(getSixRandom());
- // SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- //获取当前时间
- // Date time = Calendar.getInstance().getTime();
-
- // System.out.println(simpleDateFormat.format(datePlusOrMinus("2013-10-16 9:27:34",2)));
-
- // System.out.println(dateToString(datePlusOrMinus(getSQLDate(), 2)));
-
- // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
- // String strDate1 = "2012-3-15";
- // String strDate2 = "2013-5-13";
- // Date date1=sdf.parse(strDate1);
- // Date date2=sdf.parse(strDate2);
- // //
- // // System.out.println(getMonths(date2,date1));
- // System.out.println(daysBetween(date2, date1));
- // System.out.println(fomatDate("2014-04"));
- // System.out.println(fomatDate("2014-05"));
- // System.out.println(Double.parseDouble(fomatDate("2014-05")) > Double.parseDouble(fomatDate("2014-04")));
- // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
- // String date1 = "2014-04";
- // String date2 = "2015-08";
- // Date start = sdf.parse(date1);
- // Date end = sdf.parse(date2);
- //
- //
- // System.out.println("###start:==" + start);
- // System.out.println("###end:==" + end);
-
- // System.out.println("月份="+myTimeStr(9615000));
- // System.out.println(fomatDateToNumber("2014-07-28 14:12:14"));
- //System.out.println(compareDate("2014-08-13","2014-08-12"));
- // System.out.println(getNineRandom());
- // System.out.println("222="+dateDiffStr("2014-06-11 00:00:00","2014-06-25 23:59:59"));
-// System.out.println("getUTCTimeStr()=="+DateUtil.currentTimeDiffToHour("2015-01-22 18:12:59"));
- //System.out.println(DateUtil.dateDiff("2015-09-02 09:55:14",DateUtil.dateToString(new Date())));
- System.out.println(DateUtil.currentTimeDiff("2018-07-11 18:00:00"));
- }
-
- /**
- * 计算今天的剩余秒数
- * @return
- */
- public static int getTodaySeconds(){
- Calendar cal = Calendar.getInstance();
- long start = TimeUnit.MILLISECONDS.toSeconds(cal.getTimeInMillis());
- cal.add(Calendar.DAY_OF_YEAR, 1);
- cal.set(Calendar.MINUTE, 0);
- cal.set(Calendar.HOUR_OF_DAY, 0);
- cal.set(Calendar.SECOND, 0);
- cal.set(Calendar.MILLISECOND, 0);
- long end = TimeUnit.MILLISECONDS.toSeconds(cal.getTimeInMillis());
- return (int) (end - start);
- }
-
- /**
- * 获取当前分钟
- * @return
- */
- public static Integer getNowDateMin(){
- Calendar c1 = Calendar.getInstance();
- c1.setTime(new Date());
- return c1.get(Calendar.MINUTE);
- }
- /**
- * 获取当前day
- * @return
- */
- public static Integer getNowDateDay(){
- Calendar c1 = Calendar.getInstance();
- c1.setTime(new Date());
- return c1.get(Calendar.DATE);
- }
-
- /**
- * 获取当前秒
- * @return
- */
- public static Integer getNowDateSecond(){
- Calendar c1 = Calendar.getInstance();
- c1.setTime(new Date());
- return c1.get(Calendar.SECOND);
- }
- /**
- * 返回两个日期之间相差天数---只比较天数
- * @param fDate
- * @param oDate
- * @return
- */
- public static int daysOfTwo(Date fDate, Date oDate) {
-
- Calendar aCalendar = Calendar.getInstance();
-
- aCalendar.setTime(fDate);
-
- int day1 = aCalendar.get(Calendar.DAY_OF_YEAR);
-
- aCalendar.setTime(oDate);
-
- int day2 = aCalendar.get(Calendar.DAY_OF_YEAR);
-
- return Math.abs(day2 - day1);
-
- }
-
- /**
- * 把日期格式转换为字符串格式HH:mm:ss
- * @param date
- * @return
- */
- public static String dateToStringHMS (Date date){
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
- return simpleDateFormat.format(date);
- }
- /**
- * 把日期格式转换为字符串格式HH:mm
- * @param date
- * @return
- */
- public static String dateToStringHM (Date date){
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
- return simpleDateFormat.format(date);
- }
- /**
- * 把日期格式转换为字符串格式HHmm
- * @param date
- * @return
- */
- public static int dateToIntHM (Date date){
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HHmm");
- return Integer.parseInt(simpleDateFormat.format(date));
- }
- /**
- * 指定格式日期往后加多少分钟
- * @param format
- * @param StrDate
- * @param min
- * @return
- */
- @SuppressWarnings("static-access")
- public static String addMin(String format,String StrDate,int min){
- Calendar cal = Calendar.getInstance();
- SimpleDateFormat sFmt = new SimpleDateFormat(format);
- cal.setTime(sFmt.parse( (StrDate), new ParsePosition(0)));
-
- if (min != 0) {
- cal.add(cal.MINUTE,min);
- }
- return sFmt.format(cal.getTime());
- }
- /**
- * 指定格式日期往后加多少分钟
- * @param date
- * @param min
- * @return
- */
- public static Date addMin(Date date,int min){
- Calendar cal = Calendar.getInstance();
- cal.setTime(date);
- if (min != 0) {
- cal.add(Calendar.MINUTE,min);
- }
- return cal.getTime();
- }
- /**
- * HH:mm:ss上加秒
- * @param date
- * @param seconds
- * @return
- */
- public static String addSecond(Date date, int seconds) {
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(date);
- calendar.add(Calendar.SECOND, seconds);
- date =calendar.getTime();
- return dateToStringHMS(date);
- }
-
- /**
- * 产生2位
- */
- public static String getThreeRandom(){
- int random1 = (int) (Math.random() * 900 + 100);
- String random = String.valueOf(random1);
- return random;
- }
-
- /**
- * 把日期格式转换为字符串格式yyyy-MM-dd
- * @param
- * @return
- */
- public static String dateToStringYMD (){
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
- return simpleDateFormat.format(new Date());
- }
- /**
- * 把日期格式转换为字符串格式yyyy-MM-dd
- * @param
- * @return
- */
- public static String dateToStringYMD (Date data){
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
- return simpleDateFormat.format(data);
- }
-
- /**
- * String类型时间转为Timestamp,str与format必须格式一致
- *
- * @param str
- * @param
- * @return
- */
- public static Timestamp str2Timestamp(String str) {
- Timestamp ts = null;
- try {
- if (null != str && !"".equals(str)) {
- DateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
- ts = new Timestamp(sdf.parse(str).getTime());
- }
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- return ts;
- }
-
- /**
- * Date类型时间转为String格式,format为需要返回的格式
- *
- * @param
- * @param
- * @return
- */
- public static String timeStamp2Str(Date dateTime) {
- /*SimpleDateFormat oldFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date = new Date();
- try {
- date = oldFormat.parse(dateTime);
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }*/
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
- return sdf.format(dateTime);
- }
-
- /**
- * 获取一个月的天数
- * @param year
- * @param month
- * @return
- */
- public static int dateToString (String year,String month){
- Calendar c= Calendar.getInstance();
- c.set(Calendar.YEAR, Integer.parseInt(year));
- c.set(Calendar.MONTH, Integer.parseInt(month)+1);
- return c.getActualMaximum(Calendar.DAY_OF_MONTH);
- }
-
- /**
- * 把日期格式转换为字符串格式
- * @param date
- * @return
- */
- public static String dateToString (Date date){
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- return simpleDateFormat.format(date);
- }
- /**
- * 把日期格式转换为字符串格式
- * @param date
- * @return
- */
- public static String dateToString (Date date,String dateFormat){
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
- return simpleDateFormat.format(date);
- }
-
- /**
- * 把日期格式转换为YYMMDDHHMMSS格式
- * @param
- * @return
- */
- public static String dateToNumber (String time){
- SimpleDateFormat oldFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- SimpleDateFormat newFormat = new SimpleDateFormat("yyMMddHHmmss");
- Date date = new Date();
- try {
- date = oldFormat.parse(time);
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return newFormat.format(date);
- }
-
- /**
- * 根据有效期格式化时间
- * @param type 1每年 2 每月 3 每天 4 每小时 5 每分钟
- * @param time yyMMddHHmmss
- * @return
- */
- public static String termvalidityFormat(int type,String time){
- String retime = null;
- try {
-
- if(type == 1){
- retime = "00"+time.substring(2, time.length());
- }else if(type == 2){
- retime = "0000"+time.substring(4, time.length());
- }else if(type == 3){
- retime = "000000"+time.substring(6, time.length());
- }else if(type == 4){
- retime = "00000000"+time.substring(8, time.length());
- }else if(type == 5){
- retime = "0000000000"+time.substring(10, time.length());
- }else {
- retime = time;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- return retime;
-
- }
-
- /**
- * 把原始字符串扩展成自定的长度
- * @param oriStr 原始字符串
- * @param fillChar 要填充的字符
- * @param setLength 要扩展成的长度
- * @param preFill 前扩充还是后扩充 true-在前面填充,false-后面填充
- * @return
- */
- public static String fixStringToSetLength(String oriStr, String fillChar, int setLength, boolean preFill) {
- if(oriStr == null || fillChar.equals("")) {
- return oriStr;
- }
-
- int oriLength = oriStr.length();
- StringBuilder sb = null;
- if(preFill == true) {
- sb = new StringBuilder();
- for(int i = oriLength; i < setLength; i++) {
- sb.append(fillChar);
- }
- sb.append(oriStr);
- } else {
- sb = new StringBuilder(oriStr);
- for(int i = oriLength; i < setLength; i++) {
- sb.append(fillChar);
- }
- }
-
- return sb.toString();
- }
-
-
-
- //日期往后加多少个月,多少天,多少年
- @SuppressWarnings("static-access")
- public static String addMonth(String format,String StrDate,int year,int month,int day){
-
- Calendar cal = Calendar.getInstance();
- SimpleDateFormat sFmt = new SimpleDateFormat(format);
- cal.setTime(sFmt.parse( (StrDate), new ParsePosition(0)));
-
- if (day != 0) {
- cal.add(cal.DATE,day);
- }
- if (month != 0) {
- cal.add(cal.MONTH, month);
- }
- if (year != 0) {
- cal.add(cal.YEAR, year);
- }
- return sFmt.format(cal.getTime());
- }
-
- /**
- * 在当前时间增加或减少N个小時
- * @param
- * @param month
- * @return
- */
- public static Date addHour(int hour){
- Calendar cal = Calendar.getInstance();
- cal.add( Calendar.HOUR, hour);
- return cal.getTime();
- }
-
- /**
- * 在当前时间增加或减少N个月
- * @param
- * @param month
- * @return
- */
- public static Date addMonth(int month){
- Calendar cal = Calendar.getInstance();
- cal.add( Calendar.MONTH, month);
- return cal.getTime();
- }
-
- /**
- * 增加days天
- * @param date
- * @param days
- * @return
- */
- public static Date addDays(Date date ,int days){
- Calendar cal = Calendar.getInstance();
- cal.setTime(date);
- cal.add(Calendar.DAY_OF_MONTH, days);
- return cal.getTime();
- }
- /**
- * 判断两个时间字符串之差
- * @param date1
- * @param date2
- * @return 毫秒数
- */
- public static Long dateDiff(String date1,String date2) {
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- try {
- return df.parse(date1).getTime() - df.parse(date2).getTime();
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 判断两个指定格式时间字符串之差
- * @param format
- * @param date1
- * @param date2
- * @return 毫秒数
- */
- public static Long dateDiff(String format,String date1,String date2) {
- DateFormat df = new SimpleDateFormat(format);
- try {
- return df.parse(date1).getTime() - df.parse(date2).getTime();
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 计算时间差,相差多少天、小时、分、秒
- * @param stime
- * @param etime
- * @return
- */
- public static String dateDiffStr(String stime,String etime){
- String diff = "";
- try {
- SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- java.util.Date begin=dfs.parse(stime);
- java.util.Date end = dfs.parse(etime);
- long between=(end.getTime()-begin.getTime())/1000;//除以1000是为了转换成秒
- long day1=between/(24*3600);
- long hour1=between%(24*3600)/3600;
- long minute1=between%3600/60;
- long second1=between%60;
- System.out.println(""+day1+"天"+hour1+"小时"+minute1+"分"+second1+"秒");
- if(day1>0){
- diff = ""+day1+"天"+hour1+"小时"+minute1+"分"+second1+"秒";
- return diff;
- }
-
- if(hour1>0){
- diff = ""+hour1+"小时"+minute1+"分"+second1+"秒";
- return diff;
- }
-
- if(minute1>0){
- diff = ""+minute1+"分"+second1+"秒";
- return diff;
- }
-
- if(second1>=0){
- diff = ""+second1+"秒";
- return diff;
- }
-
- return diff;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return diff;
-
- }
-
- /**
- * 和当前时间差
- * @param date
- * @return 当前时间 - date 毫秒数
- */
- public static Long currentTimeDiff(String date) {
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- try {
- return System.currentTimeMillis() - df.parse(date).getTime();
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
- /**
- * 和当前时间差
- * @param date
- * @return 当前时间 - date 返回相差小时
- */
- public static int currentTimeDiffToHour(String date) {
- if(date == null || date.equals("")){
- return 25;
- }
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- try {
- Long longss = System.currentTimeMillis() - df.parse(date).getTime();
- int hour = Integer.parseInt(longss/(1000*3600)+"");
- return hour;
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return 25;
- }
-
- /**
- * 和当前时间差 分钟
- * @param date
- * @return 当前时间 - 返回分钟
- */
- public static int currentTimeDiffToMin(String date) {
- if(date == null || date.equals("")){
- return 25;
- }
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- try {
- Long longss = System.currentTimeMillis() - df.parse(date).getTime();
- int hour = Integer.parseInt(longss/(1000*60)+"");
- return hour;
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return 0;
- }
- /**
- * 和当前时间差(不需要时分秒)
- * @param date
- * @return 当前时间 - date
- *
- * */
- public static Long currentTimeDiff2(String date) {
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
- try {
- return System.currentTimeMillis() - df.parse(date).getTime();
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
-
-
- /**
- * 日期比较
- * @param DATE1
- * @param DATE2
- * @return DATE1 > DATE2 返回1
- */
- public static int compare_date(String DATE1, String DATE2) {
-
-
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- try {
- Date dt1 = df.parse(DATE1);
- Date dt2 = df.parse(DATE2);
- if (dt1.getTime() > dt2.getTime()) {
- return 1;
- } else if (dt1.getTime() < dt2.getTime()) {
- return -1;
- } else {
- return 0;
- }
- } catch (Exception exception) {
- exception.printStackTrace();
- }
- return 0;
- }
-
-
- /**
- * 日期比较
- * @param DATE1
- * @param DATE2
- * @return DATE1 > DATE2 返回1
- */
- public static int compareDate(String DATE1, String DATE2) {
-
- if(DATE1 == null || DATE1.equals("")){
- return -1;
- }
- if(DATE2 == null || DATE2.equals("")){
- return 1;
- }
- if(DATE1.equals(DATE2)){
- return 0;
- }
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
- try {
- Date dt1 = df.parse(DATE1);
- Date dt2 = df.parse(DATE2);
- if (dt1.getTime() > dt2.getTime()) {
- return 1;
- } else if (dt1.getTime() < dt2.getTime()) {
- return -1;
- } else {
- return 0;
- }
- } catch (Exception exception) {
- exception.printStackTrace();
- }
- return 0;
- }
-
-
- /**
- * 日期比较
- * @param DATE1
- * @param DATE2
- * @return DATE1 > DATE2 返回1
- */
- public static int compareDate(String DATE1, String DATE2,String formate) {
-
- if(DATE1 == null || DATE1.equals("")){
- return -1;
- }
- if(DATE2 == null || DATE2.equals("")){
- return 1;
- }
- if(DATE1.equals(DATE2)){
- return 0;
- }
- DateFormat df = new SimpleDateFormat(formate);
- try {
- Date dt1 = df.parse(DATE1);
- Date dt2 = df.parse(DATE2);
- if (dt1.getTime() > dt2.getTime()) {
- return 1;
- } else if (dt1.getTime() < dt2.getTime()) {
- return -1;
- } else {
- return 0;
- }
- } catch (Exception exception) {
- exception.printStackTrace();
- }
- return 0;
- }
-
-
- /**
- * 将日期yyyy-MM-dd HH:mm:ss 格式化为 yyyyMMddHHmmss
- * @param date
- * @return
- */
- public static String fomatDate(String date){
- String dateStr = null;
- if(date == null || "".equals(date)){
- dateStr = "";
- }else{
- try {
- dateStr = date.replaceAll(":", "").replaceAll("-", "").replaceAll(" ", "");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- return dateStr;
- }
-
- /**
- * 获取插入数据库格式的时间
- * @return
- */
- public static String getSQLDate() {
- String systemdate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
- .format(Calendar.getInstance().getTime()); // 获取系统当前时间
- return systemdate;
- }
-
- /**
- * 字符串转日期 yyyy-MM-dd HH:mm:ss
- * @param date
- * @return
- */
- public static Date getStringToDate(String date){
- if (StringUtils.isEmpty(date)) {
- return null;
- }
- Date date2 = new Date();
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- try {
- date2 = simpleDateFormat.parse(date);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return date2;
- }
- /**
- * 字符串转日期 yyyy-MM-dd HH:mm:ss
- * @param date
- * @return
- */
- public static Date getStringToDate(String date,String format){
- Date date2 = new Date();
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
- try {
- date2 = simpleDateFormat.parse(date);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return date2;
- }
-
- /**
- * 获取插入数据库格式的时间yyyy-MM-dd
- * @return
- */
- public static String getSQLDateYMD() {
- String systemdate = new SimpleDateFormat("yyyy-MM-dd")
- .format(Calendar.getInstance().getTime()); // 获取系统当前时间
- return systemdate;
- }
-
- public static Integer getSQLDateMonth() {
- String systemdate = new SimpleDateFormat("MM")
- .format(Calendar.getInstance().getTime()); // 获取系统当前时间
- return Integer.parseInt(systemdate);
- }
-
- /**
- * 对月份进行加减
- * @param i
- * @return
- * @throws ParseException
- */
- public static Date datePlusOrMinus(String systime ,Integer i) throws ParseException{
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date systDate =df.parse(systime);
- GregorianCalendar gc =new GregorianCalendar();
- gc.setTime(systDate);
- gc.add(2,i);
- return gc.getTime();
- }
-
- /**
- * 得到月日时分秒10位时间戳字符串
- */
- public static String getTenTimestamp() {
- String systemdate = new SimpleDateFormat("MMddHHmmss").format(Calendar.getInstance().getTime());
- return systemdate;
- }
-
-
- /**
- * 得到年月日
- */
- public static String getDateTime() {
- SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");
- String systemdate = sdf.format(Calendar.getInstance().getTime());
- return systemdate.substring(0, systemdate.length());
- }
-
- /**
- * 得到16位时间戳字符串,前面14位年月日时分秒,第15位毫秒,第16位随机数
- */
- public static String getUniqueTimestamp() {
- SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmssSSS");
- String systemdate = sdf.format(Calendar.getInstance().getTime());
- return systemdate.substring(0, systemdate.length()-2)+getOneRandom();
- }
-
- /**
- * 产生6位随机数
- */
- public static String getSixRandom(){
- int random1 = (int) (Math.random() * 900000 + 100000);
- String random = String.valueOf(random1);
- return random;
- }
-
- /**
- * 产生4位随机数
- */
- public static String getFourRandom(){
- int random1 = (int) (Math.random() * 9000 + 1000);
- String random = String.valueOf(random1);
- return random;
- }
- /**
- * 产生2位随机数
- */
- public static String getTwoRandom(){
- int random1 = (int) (Math.random() * 90 + 10);
- String random = String.valueOf(random1);
- return random;
- }
- /**
- * 产生1位随机数
- */
- public static String getOneRandom(){
- int random1 = (int) (Math.random() * 9 + 1);
- String random = String.valueOf(random1);
- return random;
- }
-
- /**
- * 产生2位小于60的随机数
- */
- public static String getTwoRandomSixth(){
- int random1 = (int) (Math.random() * 90 + 10);
- String random = String.valueOf(random1);
- return random;
- }
- /**
- * 产生-10——10之间的数字
- * @return
- */
- public static Integer randomZF(){
- int a=(int)(Math.random()*2+1);
- //System.out.println(a);
- int aa=(int)(Math.pow(-1, a));
- //System.out.println(aa);
- int aaa=(int)(Math.random()*10+1);
- int num=aa*aaa;
- //System.out.println(num);
- return num;
- }
-
- /**
- * 计算两个日期之间相差的月数
- *
- * @param date1
- * @param date2
- * @return
- */
- public static int getMonths(Date date1, Date date2) {
- int iMonth = 0;
- int flag = 0;
- try {
- Calendar objCalendarDate1 = Calendar.getInstance();
- objCalendarDate1.setTime(date1);
-
- Calendar objCalendarDate2 = Calendar.getInstance();
- objCalendarDate2.setTime(date2);
-
- if (objCalendarDate2.equals(objCalendarDate1))
- return 0;
- if (objCalendarDate1.after(objCalendarDate2)) {
- Calendar temp = objCalendarDate1;
- objCalendarDate1 = objCalendarDate2;
- objCalendarDate2 = temp;
- }
- if (objCalendarDate2.get(Calendar.DAY_OF_MONTH) < objCalendarDate1
- .get(Calendar.DAY_OF_MONTH))
- flag = 1;
-
- if (objCalendarDate2.get(Calendar.YEAR) > objCalendarDate1
- .get(Calendar.YEAR))
- iMonth = ((objCalendarDate2.get(Calendar.YEAR) - objCalendarDate1
- .get(Calendar.YEAR))
- * 12 + objCalendarDate2.get(Calendar.MONTH) - flag)
- - objCalendarDate1.get(Calendar.MONTH);
- else
- iMonth = objCalendarDate2.get(Calendar.MONTH)
- - objCalendarDate1.get(Calendar.MONTH) - flag;
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- return iMonth;
- }
-
- /**
- * 计算两个日期之间相差的天数
- *
- * @param date1
- * @param date2
- * @return
- */
- public static final int daysBetween(Date date1, Date date2) {
-
- java.util.Calendar time1 = java.util.Calendar.getInstance();
- java.util.Calendar time2 = java.util.Calendar.getInstance();
- time1.setTime(date1);
- time2.setTime(date2);
- int days = 0;
- if(time1.getTime().getTime() >= time2.getTime().getTime()){
- days = ((int) (time1.getTime().getTime() / 1000) - (int) (time2.getTime().getTime() / 1000)) / 3600 / 24;
- }else{
- days = ((int) (time2.getTime().getTime() / 1000) - (int) (time1.getTime().getTime() / 1000)) / 3600 / 24;
- }
- return days;
- }
-
- /**
- * 计算两个日期之间相差秒
- *
- * @param sdate1
- * @param sdate2
- * @return
- */
- public static final int secBetween(String sdate1, String sdate2) {
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date1 = null;
- try {
- date1 = df.parse(sdate1);
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- Date date2 = null;
- try {
- date2 = df.parse(sdate2);
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- java.util.Calendar time1 = java.util.Calendar.getInstance();
- java.util.Calendar time2 = java.util.Calendar.getInstance();
- time1.setTime(date1);
- time2.setTime(date2);
-
- int sec = 0;
- if(time1.getTime().getTime() >= time2.getTime().getTime()){
- sec = ((int) (time1.getTime().getTime() / 1000) - (int) (time2.getTime().getTime() / 1000));
- }else{
- sec = ((int) (time2.getTime().getTime() / 1000) - (int) (time1.getTime().getTime() / 1000));
- }
- return sec;
- }
-
- /**
- *
- * @param date1 <String>
- * @param date2 <String>
- * @return int
- * @throws ParseException
- */
- public static int getMonthSpace(String date1, String date2)
- throws ParseException {
-
- int result = 0;
-
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
-
- Calendar c1 = Calendar.getInstance();
- Calendar c2 = Calendar.getInstance();
-
- c1.setTime(sdf.parse(date1));
- c2.setTime(sdf.parse(date2));
-
- result = c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH);
-
- return result == 0 ? 1 : Math.abs(result);
-
- }
-
- /**
- * 根据毫秒数计算时分秒
- * @param timeMillis
- * @return
- */
- public static String myTimeStr(long timeMillis) {
- int timezone = 8;
- long totalSeconds = timeMillis / 1000;
- totalSeconds += 60 * 60 * timezone;
- int second = (int)(totalSeconds % 60);// 秒
- long totalMinutes = totalSeconds / 60;
- int minute = (int)(totalMinutes % 60);// 分
- long totalHours = totalMinutes / 60;
- int hour = (int)(totalHours % 24);// 时
- int totalDays = (int)(totalHours / 24);
-
- int _year = 1970;
-
- int year = _year + totalDays / 366;
- int month = 1;
- int day = 1;
-
- int diffDays;
- boolean leapYear;
- while (true) {
- int diff = (year - _year) * 365;
- diff += (year - 1) / 4 - (_year - 1) / 4;
- diff -= ((year - 1) / 100 - (_year - 1) / 100);
- diff += (year - 1) / 400 - (_year - 1) / 400;
-
- diffDays = totalDays - diff;
-
- leapYear = (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
- if (!leapYear && diffDays < 365 || leapYear && diffDays < 366) {
- break;
- } else {
- year++;
- }
- }
-
- int[] monthDays;
- if (diffDays >= 59 && leapYear) {
- monthDays = new int[]{-1,0,31,60,91,121,152,182,213, 244, 274, 305, 335 };
- } else {
- monthDays = new int[]{-1,0,31,59,90,120,151,181,212, 243, 273, 304, 334 };
- }
- for (int i = monthDays.length - 1; i >= 1; i--) {
- if (diffDays >= monthDays[i]) {
- month = i;
- day = diffDays - monthDays[i] + 1;
- break;
- }
- }
-
- return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
-
- }
- /**
- * 根据秒数计算小时
- * @param
- * @return
- */
- public static String secondToHour(String second) {
- if(second == null || "".equals(second) || "null".equals(second)){
- return null;
- }
- Double sec = Double.parseDouble(second);
- Double hour = sec/3600;
- DecimalFormat df=new DecimalFormat("0.0");
- return df.format(hour).toString();
- }
- /**
- * 根据秒数计算分钟
- * @param
- * @return
- */
- public static String secondToMinute(String second) {
- if(second == null || "".equals(second) || "null".equals(second)){
- return null;
- }
- Double sec = Double.parseDouble(second);
- Double minute = sec/60;
- DecimalFormat df=new DecimalFormat("0.0");
- return df.format(minute).toString();
- }
- /**
- * 根据小时数计算秒
- * @param
- * @return
- */
- public static String hourToSecond(String hour) {
- if(hour == null || "".equals(hour) || "null".equals(hour)){
- return null;
- }
- DecimalFormat df=new DecimalFormat("0");
- return df.format(Double.parseDouble(hour)*3600).toString();
- }
- /**
- * 根据分钟计算秒
- * @param
- * @return
- */
- public static String MinuteToSecond(String minute) {
- if(minute == null || "".equals(minute) || "null".equals(minute)){
- return null;
- }
- DecimalFormat df=new DecimalFormat("0");
- return df.format(Double.parseDouble(minute)*60).toString();
- }
-
- /**
- * 将日期yyyy-MM-dd HH:mm:ss 格式化为 yyMMddHHmmss
- * @param date
- * @return
- */
- public static String fomatDateToNumber(String date){
- String dateStr = null;
- if(date == null || "".equals(date)){
- dateStr = "";
- }else{
- try {
- dateStr = date.replaceAll(":", "").replaceAll("-", "").replaceAll(" ", "");
- dateStr = dateStr.substring(2);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- return dateStr;
- }
-
- /**
- * 把YYMMDDHHMMSS格式转换为date格式
- * @param
- * @return
- */
- public static String numberToDate (String number){
- SimpleDateFormat oldFormat = new SimpleDateFormat("yyMMddHHmmss");
- SimpleDateFormat newFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date = new Date();
- try {
- date = oldFormat.parse(number);
- } catch (ParseException e) {
- e.printStackTrace();
- return null;
- }
- return newFormat.format(date);
- }
-
- /**
- * 产生8位HHmmss
- */
- public static String getEightRandom(){
- String systemdate = new SimpleDateFormat("HHmmss")
- .format(Calendar.getInstance().getTime()); // 获取系统当前时间
- int random1 = (int) (Math.random() * 90 + 10);
- String random = String.valueOf(random1);
- return systemdate + random;
- }
-
- /**
- * 时间戳转换成时间
- * @param time
- * @return
- */
- public static String TimeStampToDateTime(long time){
- String datetime = null;
- try {
- SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
- datetime = sdf.format(new Date(time*1000));
- } catch (Exception e) {
- e.printStackTrace();
- }
- return datetime;
- }
-
-
- /**
- * 时间转成时间戳 毫秒
- * @param datetime
- * @return
- */
- public static long DateTimeToTimeStampSS(String datetime){
- try {
- SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
- Date date=simpleDateFormat.parse(datetime);
- long timeStemp = date.getTime();
- return timeStemp;
- } catch (Exception e) {
- e.printStackTrace();
- return 0L ;
- }
-
- }
-
- /**
- * 时间转成时间戳 秒
- * @param datetime
- * @return
- */
- public static long DateTimeToTimeStampS(String datetime){
- try {
- SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
- Date date=simpleDateFormat.parse(datetime);
- long timeStemp = date.getTime()/1000;
- return timeStemp;
- } catch (Exception e) {
- e.printStackTrace();
- return System.currentTimeMillis()/1000 ;
- }
-
- }
-
- /**
- * 转成时间戳
- * @param datetime
- * @return
- */
- public static long NumberTimeToTimeStamp(String datetime){
- try {
- SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyMMddHHmmss");
- Date date=simpleDateFormat.parse(datetime);
- long timeStemp = date.getTime()/1000;
- return timeStemp;
- } catch (Exception e) {
- e.printStackTrace();
- return System.currentTimeMillis()/1000 ;
- }
-
- }
-
- /**
- * 得到UTC时间,类型为字符串,格式为"yyyy-MM-dd HH:mm"<br />
- * 如果获取失败,返回null
- * @return
- */
- public static String getUTCTimeStr() {
- SimpleDateFormat foo = new SimpleDateFormat("yyyy-MM-dd hh:mm");
- System.out.println("foo:"+foo.format(new Date()));
-
- Calendar gc = GregorianCalendar.getInstance();
- System.out.println("gc.getTime():"+gc.getTime());
- System.out.println("gc.getTimeInMillis():"+new Date(gc.getTimeInMillis()));
-
- //当前系统默认时区的时间:
- Calendar calendar=new GregorianCalendar();
- System.out.print("时区:"+calendar.getTimeZone().getID()+" ");
- System.out.println("时间:"+calendar.get(Calendar.HOUR_OF_DAY)+":"+calendar.get(Calendar.MINUTE));
- //美国洛杉矶时区
- TimeZone tz=TimeZone.getTimeZone("America/Los_Angeles");
- //时区转换
- calendar.setTimeZone(tz);
- System.out.print("时区:"+calendar.getTimeZone().getID()+" ");
- System.out.println("时间:"+calendar.get(Calendar.HOUR_OF_DAY)+":"+calendar.get(Calendar.MINUTE));
-
- //1、取得本地时间:
- java.util.Calendar cal = java.util.Calendar.getInstance();
-
- //2、取得时间偏移量:
- int zoneOffset = cal.get(java.util.Calendar.ZONE_OFFSET);
-
- //3、取得夏令时差:
- int dstOffset = cal.get(java.util.Calendar.DST_OFFSET);
-
- //4、从本地时间里扣除这些差量,即可以取得UTC时间:
- cal.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
-
- //之后调用cal.get(int x)或cal.getTimeInMillis()方法所取得的时间即是UTC标准时间。
- System.out.println("UTC:"+new Date(cal.getTimeInMillis()));
-
- Calendar calendar1 = Calendar.getInstance();
- TimeZone tztz = TimeZone.getTimeZone("GMT");
- calendar1.setTimeZone(tztz);
- System.out.println(calendar.getTime());
- System.out.println("9999:"+calendar.getTimeInMillis()/1000);
-
- System.out.println("utc1="+System.currentTimeMillis()/1000);
- System.out.println("utc="+new Date().getTime()/1000);
-
-
- System.out.println(TimeStampToDateTime(1421724351));
- System.out.println("=="+DateTimeToTimeStampS("2015-01-20 11:35:06"));
- System.out.println(TimeStampToDateTime(DateTimeToTimeStampS("2015-01-20 11:35:06")));
- return null;
- }
-
- /**
- * 获得指定日期的前/后n天,小时
- *
- * @param specifiedDay
- * @return
- */
- public static String getSpecifiedDayAbove(String specifiedDay,int n,int h) {
- Calendar c = Calendar.getInstance();
- Date date = null;
- try {
- date = new SimpleDateFormat("yy-MM-dd HH:mm:ss").parse(specifiedDay);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- c.setTime(date);
- int day = c.get(Calendar.DATE);
- c.set(Calendar.DATE, day + n);
- int hour = c.get(Calendar.HOUR);
- c.set(Calendar.HOUR,hour + h);
-
- String dayAfter = new SimpleDateFormat("yy-MM-dd HH:mm:ss")
- .format(c.getTime());
- return dayAfter;
- }
-
- /**
- * 两个时间的小时差
- * @param st
- * @param ed
- * @return
- */
- public static long dateSpaceHours(Date st,Date ed){
- return (long) Math.ceil((ed.getTime() - st.getTime())/3600000.0);
- }
-
- public static String formatDate(Date date, String format) throws ParseException {
- DateFormat df = new SimpleDateFormat(format);
- df.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
- return df.format(date);
- }
- public static Date parseDate(String date, String format) {
- DateFormat df = new SimpleDateFormat(format);
- df.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
- try {
- return df.parse(date);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return null;
- }
-}
-
-
-
-
-
-
-
-
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/EosService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/EosService.java
deleted file mode 100644
index 4aad013..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/EosService.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.blackchain.model.EosResult;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class EosService {
- // 正式网络 https://api-v2.eosasia.one https://proxy.eosnode.tools
- // 测试网络 https://api-kylin.eosasia.one
- // "eosqxyx11111", "5JJB2oiCXwASK9fumjyTgbtHcwDVedVRaZda1kBhFuQcmjnrDWB"
- //private final static String account = "huobideposit";
- public final static String ACCOUNT = "biueeostoken";
- // private String account;
- private final static String EOS_NAME = "EOS";
- public static final String K_mnemonic = "mnemonic";
- public static final String K_privateKey = "privateKey";
- public static final String K_publicKey = "publicKey";
- private static final String EOS_TOKEN = "eosio.token";
- private static final String ACTION_TRANSFER = "transfer";
-
-
- public static void main(String[] args) throws Exception {
-
- List<EosResult> actions = getActions(0, 3);
- for(EosResult eosResult:actions){
- System.out.println(eosResult.toString());
- String quantity = eosResult.getQuantity();
- String amountStr = quantity.split("")[0];
- System.out.println(quantity);
- System.out.println(new BigDecimal(amountStr));
- }
- }
-
-
- /**
- *
- * @param pos 从第几条开始(包括pos)
- * @param offset 查询条数
- * @return
- */
- public static List<EosResult> getActions(int pos, int offset) {
- JSONObject param = new JSONObject();
- param.put("account_name", ACCOUNT);
- param.put("pos", pos);
- param.put("offset", offset);
- Map<String, String> header = new HashMap<String, String>();
- header.put("content-type", "application/json");
- String res = HttpUtil.post("https://api.eosflare.io/v1/eosflare/get_actions", null, param.toJSONString(), header);
- System.out.println(res);
- List<EosResult> results = new ArrayList<>();
- try {
-
- JSONObject jsonObject = JSONObject.parseObject(res);
- JSONArray actions = jsonObject.getJSONArray("actions");
- if (actions != null && actions.size() > 0) {
- int size = actions.size();
- EosResult eosResult = null;
- for (int i = 0; i < size; i++) {
- JSONObject jsonObject1 = actions.getJSONObject(i);
- // 当前交易序号
- Object account_action_seq = jsonObject1.get("account_action_seq");
- JSONObject action_trace = jsonObject1.getJSONObject("action_trace");
- JSONObject act = action_trace.getJSONObject("act");
- Object account = act.get("account");
- if (!EOS_TOKEN.equals(account)) {
- continue;
- }
- eosResult = JSONObject.parseObject(act.getString("data"), EosResult.class);
- eosResult.setAccountActionSeq((Integer) account_action_seq);
- results.add(eosResult);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return results;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/EthService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/EthService.java
deleted file mode 100644
index 5638359..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/EthService.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import java.io.File;
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-import org.web3j.abi.FunctionEncoder;
-import org.web3j.abi.FunctionReturnDecoder;
-import org.web3j.abi.TypeReference;
-import org.web3j.abi.datatypes.Address;
-import org.web3j.abi.datatypes.Function;
-import org.web3j.abi.datatypes.Type;
-import org.web3j.abi.datatypes.generated.Uint256;
-import org.web3j.crypto.Credentials;
-import org.web3j.crypto.RawTransaction;
-import org.web3j.crypto.TransactionEncoder;
-import org.web3j.crypto.WalletUtils;
-import org.web3j.protocol.Web3j;
-import org.web3j.protocol.admin.Admin;
-import org.web3j.protocol.core.DefaultBlockParameterName;
-import org.web3j.protocol.core.Request;
-import org.web3j.protocol.core.methods.request.Transaction;
-import org.web3j.protocol.core.methods.response.*;
-import org.web3j.protocol.http.HttpService;
-import org.web3j.utils.Convert;
-import org.web3j.utils.Numeric;
-import org.web3j.utils.Convert.Unit;
-
-/**
- * ETH类,使用Web3j 下面为使用教程
- * https://kauri.io/article/925d923e12c543da9a0a3e617be963b4/manage-an-ethereum-account-with-java-and-web3js
- *
- * @author Administrator
- *
- */
-
-public class EthService {
-
- private static String ethWalletPath = "/home/javaweb/webresource/eth";
- // private static String ethWalletPath="E://";
- private Web3j web3j;
- // private Admin admin;
- // private Parity parity;
- /**
- * 服务器地址
- */
- //private static final String ETH_UTL = "https://mainnet.infura.io/v3/882c66ebcfc141abbea22b948fa44321";
- private static final String ETH_UTL = "http://120.55.86.146:8545";
-
- public EthService() {
- try {
- HttpService service = new HttpService(ETH_UTL);
- web3j = Web3j.build(service);
- // parity = Parity.build(service);
- // admin = Admin.build(service);
- } catch (Exception e) {
- System.out.println("liangjieshibao");
- // logger.error("==============虚拟币-以太坊链接获取失败!");
- e.printStackTrace();
- }
- }
-
- /**
- * 查询ETH余额
- *
- * @param address
- * @return
- */
- public static BigDecimal getEthBlance(String address) {
- Web3j web3 = Web3j.build(new HttpService(ETH_UTL));
- EthGetBalance balanceWei;
- try {
- balanceWei = web3.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();
- if (balanceWei.getResult() == null) {
- return null;
- }
- BigDecimal balanceInEther = Convert.fromWei(balanceWei.getBalance().toString(), Unit.ETHER);
- return balanceInEther;
- } catch (Exception e) {
- System.out.println("ETH查询失败:" + address);
- e.printStackTrace();
- }
- return null;
-
- }
-
- /**
- * 创建ETH钱包
- *
- * @return
- */
- public static Map<String, String> createEth() {
- Map<String, String> wallet = new HashMap<String, String>();
- try {
- String walletPassword = "secr3t";
- // 文件路径
- String walletDirectory = ethWalletPath;
-
- String walletName = WalletUtils.generateNewWalletFile(walletPassword, new File(walletDirectory));
- System.out.println("wallet location: " + walletDirectory + "/" + walletName);
- Credentials credentials = WalletUtils.loadCredentials(walletPassword, walletDirectory + "/" + walletName);
- String accountAddress = credentials.getAddress();
- String privateKey = credentials.getEcKeyPair().getPrivateKey().toString(16);
- // 钱包地址
- wallet.put("address", accountAddress);
- // 钱包私钥
- wallet.put("privateKey", privateKey);
- // 产生的钱包文件地址
- wallet.put("walletLocation", walletDirectory + "/" + walletName);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return wallet;
- }
-
- public boolean checkTransferResult(String hash) {
- // 0xa3e6a0ccc3aac30d866a86ca9c0477dd58b7b061787ba40b16c3844803273816 交易hash
- Request<?, EthGetTransactionReceipt> ethGetTransactionReceiptRequest = web3j.ethGetTransactionReceipt(hash);
- EthGetTransactionReceipt send = null;
- try {
- send = ethGetTransactionReceiptRequest.send();
- if(send!=null){
- TransactionReceipt result = send.getResult();
- if(result!=null){
- String status = result.getStatus();
- System.out.println(status);//0x1
- if("0x1".equals(status)){
- return true;
- }else{
- return false;
- }
- }
-
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- return false;
- }
-
- public static void main(String[] args) throws IOException {
- HttpService service = new HttpService(ETH_UTL);
- Web3j build = Web3j.build(service);
- //Request<?, EthTransaction> ethTransactionRequest = build.ethGetTransactionByHash("0xa3e6a0ccc3aac30d866a86ca9c0477dd58b7b061787ba40b16c3844803273816");
- Request<?, EthGetTransactionReceipt> ethGetTransactionReceiptRequest = build.ethGetTransactionReceipt("0xa3e6a0ccc3aac30d866a86ca9c0477dd58b7b061787ba40b16c3844803273816");
- EthGetTransactionReceipt send = ethGetTransactionReceiptRequest.send();
- String status = send.getResult().getStatus();
- System.out.println(status);//0x1
-// EthTransaction send = ethTransactionRequest.send();
-// String input = send.getResult().getInput();
-// System.out.println(input);
- }
-
- /**
- *
- * 方法描述:获取代币余额
- *
- * @param fromAddress
- * @param
- * @param
- * @return long
- */
- public BigDecimal tokenGetBalance(String fromAddress) {
- try {
- // 合约地址
- String contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7";
- int decimal = 6;
- String methodName = "balanceOf";
- List<Type> inputParameters = new ArrayList<>();
- List<TypeReference<?>> outputParameters = new ArrayList<>();
- Address address = new Address(fromAddress);
- inputParameters.add(address);
- TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
- };
- outputParameters.add(typeReference);
- Function function = new Function(methodName, inputParameters, outputParameters);
- String data = FunctionEncoder.encode(function);
- Transaction transaction = Transaction.createEthCallTransaction(fromAddress, contractAddress, data);
-
- EthCall ethCall;
- BigInteger balanceValue = BigInteger.ZERO;
- try {
- ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
- List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
- balanceValue = (BigInteger) results.get(0).getValue();
- } catch (IOException e) {
- e.printStackTrace();
- }
- double res = BigDecimalUtil.div(new BigDecimal(balanceValue).doubleValue(), Math.pow(10, decimal), 8);
- if (res > 0) {
- return new BigDecimal(res);
- }
- } catch (Exception e) {
- // logger.error("==============以太坊代币链接获取失败!");
- e.printStackTrace();
- }
- return BigDecimal.ZERO;
- }
-
- // USDT
- public String tokenSend(String privateKey, String fromAddress, String toAddress, String amount)
- throws InterruptedException, ExecutionException {
- // Web3j web3j = Web3j.build(new
- // HttpService("https://mainnet.infura.io/v3/882c66ebcfc141abbea22b948fa44321"));
- String contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7";
- Credentials credentials = Credentials.create(privateKey);
-
- EthGetTransactionCount ethGetTransactionCount = web3j
- .ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
-
- BigInteger nonce = ethGetTransactionCount.getTransactionCount();
-
- Function function = new Function("transfer",
- Arrays.asList(new Address(toAddress), new Uint256(new BigInteger(amount))),
- Arrays.asList(new TypeReference<Type>() {
- }));
-
- String encodedFunction = FunctionEncoder.encode(function);
-
- RawTransaction rawTransaction = RawTransaction.createTransaction(nonce,
- Convert.toWei("70", Convert.Unit.GWEI).toBigInteger(),// 给矿工开的转账单价 单价越高越快
- Convert.toWei("60000", Convert.Unit.WEI).toBigInteger(), contractAddress, encodedFunction);//里程上限
- // 10*80000/1000000000=0.0008 手续费
-
- byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
- String hexValue = Numeric.toHexString(signedMessage);
-
- // log.debug("transfer hexValue:" + hexValue);
-
- EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
-
-
- if (ethSendTransaction.hasError()) {
- // log.info("transfer error:", ethSendTransaction.getError().getMessage());
- return "";
- } else {
- String transactionHash = ethSendTransaction.getTransactionHash();
- // log.info("Transfer transactionHash:" + transactionHash);
- return transactionHash;
- }
- }
-
- public String ethSend(String privateKey, String fromAddress, String toAddress, String amount)
- throws InterruptedException, ExecutionException {
- // Web3j web3j = Web3j.build(new
- // HttpService("https://mainnet.infura.io/v3/882c66ebcfc141abbea22b948fa44321"));
-
- Credentials credentials = Credentials.create(privateKey);
-
- EthGetTransactionCount ethGetTransactionCount = web3j
- .ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
-
- BigInteger nonce = ethGetTransactionCount.getTransactionCount();
- BigInteger value = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger();
- RawTransaction rawTransaction = RawTransaction.createEtherTransaction(nonce,
- Convert.toWei("50", Convert.Unit.GWEI).toBigInteger(),
- Convert.toWei("60000", Convert.Unit.WEI).toBigInteger(), toAddress, value);
- byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
- String hexValue = Numeric.toHexString(signedMessage);
-
- EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
- if (ethSendTransaction.hasError()) {
- // log.info("transfer error:", ethSendTransaction.getError().getMessage());
- return "";
- } else {
- String transactionHash = ethSendTransaction.getTransactionHash();
- // log.info("Transfer transactionHash:" + transactionHash);
- return transactionHash;
- }
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/HttpUtil.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/HttpUtil.java
deleted file mode 100644
index a146fe4..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/HttpUtil.java
+++ /dev/null
@@ -1,281 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-/**
- * @author: DengJiong
- * @date: 2018-05-09 18:43
- * @description:
- */
-
-import org.apache.commons.lang3.StringUtils;
-
-import javax.net.ssl.*;
-import java.io.*;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * http 工具类
- *
- * @author cloud cloud
- * @create 2017/10/18
- **/
-public class HttpUtil {
-
- private static final String CHARSET = "UTF-8";
- private static final String HTTP_POST = "POST";
- private static final String HTTP_GET = "GET";
-
- private static final String HTTP_PUT = "PUT";
-
- /**
- * Send GET request
- */
- public static String get(String url, Map<String, String> queryParas, Map<String, String> headers) {
- HttpURLConnection conn = null;
- try {
- conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), HTTP_GET, headers);
- conn.connect();
- return readResponseString(conn);
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- }
-
- public static String get(String url, Map<String, String> queryParas) {
- return get(url, queryParas, null);
- }
-
- public static String get(String url) {
- return get(url, null, null);
- }
-
- public static String jsonGet(String url,Map<String,String> params){
- Map<String,String> headers = new HashMap<>();
- headers.put("Content-Type","application/json");
- return get(url,params,headers);
- }
-
-
- /**
- * Send POST request
- */
- public static String post(String url, Map<String, String> queryParas, String data, Map<String, String> headers) {
- HttpURLConnection conn = null;
- try {
- conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), HTTP_POST, headers);
- conn.connect();
- OutputStream out = conn.getOutputStream();
- out.write(data.getBytes(CHARSET));
- out.flush();
- out.close();
- return readResponseString(conn);
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- }
-
- public static String post(String url, Map<String, String> queryParas, String data) {
- return post(url, queryParas, data, null);
- }
-
- public static String post(String url, String data, Map<String, String> headers) {
- return post(url, null, data, headers);
- }
-
- public static String post(String url, String data) {
- return post(url, null, data, null);
- }
-
- public static String jsonPost(String url,String data){
- Map<String,String> headers = new HashMap<>();
- headers.put("Content-Type","application/json");
- return post(url,null,data,headers);
- }
-
- public static String jsonPost(String url,Map<String,String>headers,String data){
- if(headers == null){
- headers = new HashMap<>();
- }
- headers.put("Content-Type","application/json");
- return post(url,null,data,headers);
- }
-
- /**
- * Send POST request
- */
- public static String put(String url, Map<String, String> queryParas, String data, Map<String, String> headers) {
- HttpURLConnection conn = null;
- try {
- conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), HTTP_PUT, headers);
- conn.connect();
- OutputStream out = conn.getOutputStream();
- out.write(data.getBytes(CHARSET));
- out.flush();
- out.close();
- return readResponseString(conn);
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- }
-
-
-
- public static String jsonPut(String url,String data){
- Map<String,String> headers = new HashMap<>();
- headers.put("Content-Type","application/json");
- return put(url,null,data,headers);
- }
-
-
- /**
- * https 域名校验
- */
- private static class TrustAnyHostnameVerifier implements HostnameVerifier {
- @Override
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- }
-
- /**
- * https 证书管理
- */
- private static class TrustAnyTrustManager implements X509TrustManager {
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- }
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- }
- }
-
- private static SSLSocketFactory initSSLSocketFactory() {
- try {
- TrustManager[] tm = {new TrustAnyTrustManager()};
- SSLContext sslContext = SSLContext.getInstance("TLS", "SunJSSE");
- sslContext.init(null, tm, new java.security.SecureRandom());
- return sslContext.getSocketFactory();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();
- private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new TrustAnyHostnameVerifier();
-
- private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers) throws Exception {
- URL _url = new URL(url);
- HttpURLConnection conn = (HttpURLConnection)_url.openConnection();
- if (conn instanceof HttpsURLConnection) {
- ((HttpsURLConnection)conn).setSSLSocketFactory(sslSocketFactory);
- ((HttpsURLConnection)conn).setHostnameVerifier(trustAnyHostnameVerifier);
- }
- conn.setRequestMethod(method);
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setConnectTimeout(30000);
- conn.setReadTimeout(30000);
- conn.setUseCaches(false); // Post 请求不能使用缓存
- if(headers != null){
- String contentType = headers.get("Content-Type");
- if(StringUtils.isNotEmpty(contentType)){
- conn.setRequestProperty("Content-Type",contentType);
- }else{
- conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=utf-8");
- }
- }
- conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");
- if (headers != null && !headers.isEmpty())
- for (Map.Entry<String, String> entry : headers.entrySet())
- conn.setRequestProperty(entry.getKey(), entry.getValue());
-
- return conn;
- }
-
- private static String readResponseString(HttpURLConnection conn) {
- StringBuilder sb = new StringBuilder();
- InputStream inputStream = null;
- try {
- inputStream = conn.getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, CHARSET));
- String line = null;
- while ((line = reader.readLine()) != null){
- sb.append(line).append("\n");
- }
- return sb.toString();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- /**
- * Build queryString of the url
- */
- private static String buildUrlWithQueryString(String url, Map<String, String> queryParas) {
- if (queryParas == null || queryParas.isEmpty())
- return url;
-
- StringBuilder sb = new StringBuilder(url);
- boolean isFirst;
- if (url.indexOf("?") == -1) {
- isFirst = true;
- sb.append("?");
- }
- else {
- isFirst = false;
- }
-
- for (Map.Entry<String, String> entry : queryParas.entrySet()) {
- if (isFirst) isFirst = false;
- else sb.append("&");
-
- String key = entry.getKey();
- String value = entry.getValue();
- if (!StringUtils.isEmpty(value)){
- try {value = URLEncoder.encode(value, CHARSET);} catch (UnsupportedEncodingException e) {throw new RuntimeException(e);}
- sb.append(key).append("=").append(value);
- }
- }
- return sb.toString();
- }
-}
-
-
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/Impl/BlockSeriveImpl.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/Impl/BlockSeriveImpl.java
deleted file mode 100644
index 87d9239..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/Impl/BlockSeriveImpl.java
+++ /dev/null
@@ -1,212 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service.Impl;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.Resource;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.blackchain.service.BlockSerive;
-import com.xcong.excoin.modules.blackchain.service.BtcService;
-import com.xcong.excoin.modules.blackchain.service.EthService;
-import com.xcong.excoin.modules.blackchain.service.LtcService;
-import com.xcong.excoin.modules.blackchain.service.UsdtService;
-import com.xcong.excoin.modules.blackchain.service.XrpService;
-import com.xcong.excoin.modules.member.dao.MemberCoinAddressDao;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.entity.MemberCoinAddressEntity;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import com.xcong.excoin.utils.RedisUtils;
-
-@Slf4j
-@Service
-public class BlockSeriveImpl implements BlockSerive {
-
- @Resource
- RedisUtils redisUtil;
- @Resource
- MemberDao memberDao;
- @Resource
- MemberCoinAddressDao memberMapper;
-
- @Override
- public Result findBlockAddress(String symbol) {
- //获取用户ID
- String mId = LoginUserUtils.getAppLoginUser().getId().toString();
- MemberEntity member = memberDao.selectById(mId);
- if (member == null) {
- return Result.fail(MessageSourceUtils.getString("member_service_0003"));
- }
- String lable = "ERC20";
- Result result = new Result();
- try {
- Map<String, String> map = new HashMap<String, String>();
- MemberCoinAddressEntity memberCoinAddress = new MemberCoinAddressEntity();
-
- if ("USDT".equals(symbol)) {
- memberCoinAddress = memberMapper.selectBlockAddressWithTag(Long.parseLong(mId), symbol, lable);
- } else {
- memberCoinAddress = memberMapper.selectBlockAddress(Long.parseLong(mId), symbol);
- }
- log.info("--->{}", memberCoinAddress);
- if (memberCoinAddress != null) {
- map.put("address", memberCoinAddress.getAddress());
- map.put("lable", memberCoinAddress.getLabel());
- result.setData(map);
- result.setCode(0);
- } else {
- String address = "";
- String key = "";
- String uuid = member.getInviteId();
- switch (symbol) {
- case "BTC":
- Map<String, String> btcMap = UsdtService.createWallet(mId);
- address = btcMap.get("address");
- key = btcMap.get("privateKey");
- map.put("address", address);
- break;
- case "ETH":
- Map<String, String> ethMap = EthService.createEth();
- address = ethMap.get("address");
- key = ethMap.get("privateKey");
- map.put("address", address);
- break;
- case "BCH":
- MemberCoinAddressEntity btcAddress = memberMapper.selectBlockAddress(Long.parseLong(mId), "BTC");
- if (btcAddress != null) {
- address = btcAddress.getAddress();
- key = btcAddress.getPrivateKey();
- map.put("address", address);
- } else {
- Map<String, String> bchMap = BtcService.createWallet(mId);
- address = bchMap.get("address");
- key = bchMap.get("privateKey");
- map.put("address", address);
-
- MemberCoinAddressEntity coinAddress = new MemberCoinAddressEntity();
- coinAddress.setAddress(address);
- coinAddress.setIsBiyict(MemberCoinAddressEntity.IS_BIYICT_YES);
- coinAddress.setMemberId(Long.parseLong(mId));
- coinAddress.setPrivateKey(key);
- coinAddress.setSymbol("BTC");
- coinAddress.setLabel(uuid);
- memberMapper.insert(coinAddress);
- }
- break;
- case "EOS":
- address = "biyicteos123";
- map.put("address", address);
- map.put("lable", uuid);
- break;
- case "XRP":
- address = "biyicteos123";
- map.put("address", address);
- map.put("lable", uuid);
- break;
- case "LTC":
- Map<String, String> ltcMap = LtcService.createWallet(mId);
- address = ltcMap.get("address");
- key = ltcMap.get("privateKey");
- map.put("address", address);
- break;
- case "ETC":
- MemberCoinAddressEntity ethAddress = memberMapper.selectBlockAddress(Long.parseLong(mId), "ETH");
- if (ethAddress != null) {
- address = ethAddress.getAddress();
- key = ethAddress.getPrivateKey();
- map.put("address", address);
- } else {
- Map<String, String> etcMap = EthService.createEth();
- address = etcMap.get("address");
- key = etcMap.get("privateKey");
- map.put("address", address);
-
- MemberCoinAddressEntity coinAddress = new MemberCoinAddressEntity();
- coinAddress.setAddress(address);
- coinAddress.setIsBiyict(MemberCoinAddressEntity.IS_BIYICT_YES);
- coinAddress.setMemberId(Long.parseLong(mId));
- coinAddress.setPrivateKey(key);
- coinAddress.setSymbol("ETH");
- coinAddress.setLabel(uuid);
- memberMapper.insert(coinAddress);
- }
-
- break;
- case "USDT":
- if ("OMNI".equals(lable)) {
- MemberCoinAddressEntity btcAddress2 = memberMapper.selectBlockAddress(Long.parseLong(mId), "BTC");
- if (btcAddress2 != null) {
- address = btcAddress2.getAddress();
- key = btcAddress2.getPrivateKey();
- map.put("address", address);
- } else {
- //如果BTC地址不存在,创建一个BTC地址
- Map<String, String> usdtMap = UsdtService.createWallet(mId);
- address = usdtMap.get("address");
- key = usdtMap.get("privateKey");
- map.put("address", address);
-
- MemberCoinAddressEntity coinAddress = new MemberCoinAddressEntity();
- coinAddress.setAddress(address);
- coinAddress.setIsBiyict(MemberCoinAddressEntity.IS_BIYICT_YES);
- coinAddress.setMemberId(Long.parseLong(mId));
- coinAddress.setPrivateKey(key);
- coinAddress.setSymbol("BTC");
- coinAddress.setLabel(uuid);
- memberMapper.insert(coinAddress);
- }
-
- } else {
- MemberCoinAddressEntity ethAddress2 = memberMapper.selectBlockAddress(Long.parseLong(mId), "ETH");
- if (ethAddress2 != null) {
- address = ethAddress2.getAddress();
- key = ethAddress2.getPrivateKey();
- map.put("address", address);
- } else {
- Map<String, String> usdtMap = EthService.createEth();
- address = usdtMap.get("address");
- key = usdtMap.get("privateKey");
- map.put("address", address);
-
- MemberCoinAddressEntity coinAddress = new MemberCoinAddressEntity();
- coinAddress.setAddress(address);
- coinAddress.setIsBiyict(MemberCoinAddressEntity.IS_BIYICT_YES);
- coinAddress.setMemberId(Long.parseLong(mId));
- coinAddress.setPrivateKey(key);
- coinAddress.setSymbol("ETH");
- coinAddress.setLabel(uuid);
- memberMapper.insert(coinAddress);
- }
- }
- break;
- default:
- break;
- }
- MemberCoinAddressEntity coinAddress = new MemberCoinAddressEntity();
- coinAddress.setAddress(address);
- coinAddress.setIsBiyict(MemberCoinAddressEntity.IS_BIYICT_YES);
- coinAddress.setMemberId(Long.parseLong(mId));
- coinAddress.setPrivateKey(key);
- coinAddress.setSymbol(symbol);
- coinAddress.setLabel(uuid);
- if (symbol.equals("USDT")) {
- coinAddress.setTag(lable);
- }
-
- memberMapper.insert(coinAddress);
- result.setData(map);
- result.setCode(0);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/LtcService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/LtcService.java
deleted file mode 100644
index 9acd8a1..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/LtcService.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang3.StringUtils;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-
-
-public class LtcService {
-
- private static LtcService service = null;
- private final static String RESULT = "result";
- private final static String METHOD_SEND_TO_ADDRESS = "sendtoaddress";
- private final static String METHOD_GET_TRANSACTION = "gettransaction";
- private final static String METHOD_LIST_TRANSACTIONS = "listtransactions";
- private final static String METHOD_GET_BLOCK_COUNT = "getblockcount";
- private final static String METHOD_NEW_ADDRESS = "getnewaddress";
- private final static String METHOD_GET_BALANCE = "getbalance";
- private final static String METHOD_WALLET_PASSPHRASE = "walletpassphrase";
- private final static String METHOD_WALLET_LOCK = "walletlock";
- private final static String METHOD_GET_BALANCE_ADDRESS = "getreceivedbyaddress";
-
- private String url = "http://121.40.86.163:1888";
- private String username = "biyiltc";
- private String password = "biyiltc";
-
- public static LtcService getInstance() {
- if (service != null) {
- return service;
- }
- return new LtcService();
- }
-
- private LtcService() {
- }
-
- /**
- * 创建BTC钱包 每个账户对应一个地址 方便后续操作
- * @param mId 账户
- * @return
- */
- public static Map<String, String> createWallet(String mId) {
- LtcService btcService = getInstance();
- // 创建钱包地址
- String address = btcService.getAddress(mId);
- // 私钥
- String privateKey = btcService.dumpprivkey(address);
- Map<String, String> result = new HashMap<String,String>();
- result.put("address", address);
- result.put("privateKey", privateKey);
- return result;
- }
- public String getAddress(String label) {
- try {
- JSONObject json = doRequest(METHOD_NEW_ADDRESS,label);
- //JSONObject json = doRequest(METHOD_NEW_ADDRESS);
- if (isError(json)) {
- return "";
- }
- return json.getString(RESULT);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- private JSONObject doRequest(String method, Object... params) {
- JSONObject param = new JSONObject();
- param.put("id", System.currentTimeMillis() + "");
- param.put("jsonrpc", "2.0");
- param.put("method", method);
- if (params != null) {
- param.put("params", params);
- }
- String creb = Base64.encodeBase64String((username + ":" + password).getBytes());
- Map<String, String> headers = new HashMap<>(2);
- headers.put("Authorization", "Basic " + creb);
- return JSON.parseObject(HttpUtil.jsonPost(url, headers, param.toJSONString()));
- }
-
- private boolean isError(JSONObject json) {
- if (json == null || (StringUtils.isNotEmpty(json.getString("error")) && json.get("error") != "null")) {
- return true;
- }
- return false;
- }
-
- public String dumpprivkey(String address) {
- try {
- JSONObject obj = doRequest("dumpprivkey", address);
- //System.out.println(obj);
- if (!isError(obj)) {
- return obj.getString(RESULT);
- } else {
- return null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 查询给定地址的总收款额(只计算接受的)
- * @param address
- * @return
- */
- public BigDecimal getBalance(String address) {
- JSONObject json = doRequest(METHOD_GET_BALANCE_ADDRESS,address,3);
- if (!isError(json)) {
- return new BigDecimal(json.getString(RESULT));
- } else {
- return null;
- }
- }
-
- public static void main(String[] args) {
- BigDecimal s = LtcService.getInstance().getBalance("MS6UBteTkQYbbBg5xEPWUQ1PPG7zkxY368");
- System.out.println(s);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/UsdtEthService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/UsdtEthService.java
deleted file mode 100644
index b3aea54..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/UsdtEthService.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.StrUtil;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.modules.member.dao.MemberCoinAddressDao;
-import com.xcong.excoin.modules.member.dao.MemberCoinChargeDao;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
-import com.xcong.excoin.modules.member.entity.MemberCoinAddressEntity;
-import com.xcong.excoin.modules.member.entity.MemberCoinChargeEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-/**
- * @author wzy
- * @date 2020-07-03
- **/
-@Slf4j
-@Component
-public class UsdtEthService {
-
- private static final BigDecimal LIMIT = new BigDecimal("50");
- private static final BigDecimal LIMIT_ETH = new BigDecimal("0.2");
- private static final BigDecimal FEE = new BigDecimal("0.005");
- private static final BigDecimal ETH_TR_FEE = new BigDecimal("0.0032");
-
- public static String ETH_FEE = "0.005";
-
- public static final String TOTAL_ADDRESS = "0x067b4bE5d7B05560AE539Fc8f10597D854ae056D";
- public static final String TOTAL_PRIVATE = "1fb7288c8c88c37d6f79e9617822bffc8d3635bf2d808c5f6afdee9bb326e49c";
-
- @Resource
- private MemberCoinChargeDao memberCoinChargeDao;
- @Resource
- private MemberCoinAddressDao memberCoinAddressDao;
- @Resource
- private MemberWalletCoinDao memberWalletCoinDao;
-
- public void pool() throws ExecutionException, InterruptedException {
- List<MemberCoinChargeEntity> list = memberCoinChargeDao.selectAllBySymbolAndTag(CoinTypeEnum.USDT.name(), "ERC20", 1);
- if (CollUtil.isNotEmpty(list)) {
- EthService ethService = new EthService();
-
- for (MemberCoinChargeEntity coinCharge : list) {
- // 首先根据每个地址查询其是否有ETH 如果没有就充值ETH并设置1 表示初始状态 status=2(待充值)3:表示已提过
- String address = coinCharge.getAddress();
- Long memberId = coinCharge.getMemberId();
- BigDecimal lastAmount = coinCharge.getLastAmount();
- if (lastAmount == null || lastAmount.compareTo(LIMIT) < 0) {
- continue;
- }
-
- BigDecimal usdt = ethService.tokenGetBalance(address);
- log.info("地址:{}, 金额:{}", address, usdt);
- if (usdt != null && usdt.compareTo(LIMIT) > 0) {
- usdt = usdt.subtract(new BigDecimal("0.01"));
-
- // 查询eth是否足够
- BigDecimal eth = EthService.getEthBlance(address);
- log.info("地址:{}, ETH:{}", address, eth);
- if (eth != null && eth.compareTo(FEE) >= 0) {
- MemberCoinAddressEntity memberCoinAddressEntity = memberCoinAddressDao.selectBlockAddressWithTag(memberId, CoinTypeEnum.USDT.name(), "ERC20");
- if (memberCoinAddressEntity == null) {
- continue;
- }
-
- String privateKey = memberCoinAddressEntity.getPrivateKey();
-
- usdt = usdt.multiply(new BigDecimal("1000000"));
- String usdtStr = usdt.toPlainString();
- if (usdtStr.contains(".")) {
- usdtStr = usdtStr.substring(0, usdtStr.lastIndexOf("."));
- }
-
- String hash = ethService.tokenSend(privateKey, address, TOTAL_ADDRESS, usdtStr);
- log.info("归集:{}", hash);
- if (StrUtil.isNotBlank(hash)) {
- // 归集成功更新状态 先保存本次的hash值,待交易成功后再更新
- coinCharge.setHash(hash);
- memberCoinChargeDao.updateById(coinCharge);
- }
- } else {
- String hash = ethService.ethSend(TOTAL_PRIVATE, TOTAL_ADDRESS, address, ETH_FEE);
- log.info("转手续费:{}", hash);
- }
- }
- }
- }
- }
-
-
- public void ethPool() throws ExecutionException, InterruptedException {
- List<MemberCoinChargeEntity> list = memberCoinChargeDao.selectAllBySymbolAndTag(CoinTypeEnum.ETH.name(), null, 1);
- if (CollUtil.isNotEmpty(list)) {
- EthService ethService = new EthService();
- for (MemberCoinChargeEntity coinCharge : list) {
- String address = coinCharge.getAddress();
- Long memberId = coinCharge.getMemberId();
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.ETH.name());
- if (walletCoin == null) {
- continue;
- }
-
- BigDecimal earlyBalance = walletCoin.getEarlyBalance();
-
- if (earlyBalance == null || earlyBalance.compareTo(LIMIT_ETH) < 0) {
- continue;
- }
-
- BigDecimal eth = EthService.getEthBlance(address);
- if (eth != null && eth.compareTo(LIMIT_ETH) >= 0) {
- MemberCoinAddressEntity coinAddress = memberCoinAddressDao.selectBlockAddressWithTag(memberId, CoinTypeEnum.ETH.name(), null);
- String privateKey = coinAddress.getPrivateKey();
-
- BigDecimal tr = eth.subtract(ETH_TR_FEE);
- String hash = ethService.ethSend(privateKey, address, TOTAL_ADDRESS, tr.toPlainString());
- if (StrUtil.isNotBlank(hash)) {
- coinCharge.setHash(hash);
- coinCharge.setLastAmount(new BigDecimal("0.0001"));
- coinCharge.setStatus(3);
- memberCoinChargeDao.updateById(coinCharge);
- }
- }
- }
- }
- }
-
- /**
- * 定时查询该归集转账交易是否成功
- */
- public void usdtEthPoolCheck() {
- // 首先查询需要确认的交易
- List<MemberCoinChargeEntity> list = memberCoinChargeDao.selectAllBySymbolAndTag(CoinTypeEnum.USDT.name(), "ERC20", null);
- EthService ethService = new EthService();
-
- if (CollectionUtils.isNotEmpty(list)) {
- for (MemberCoinChargeEntity appeal : list) {
- String hash = appeal.getHash();
- boolean b = ethService.checkTransferResult(hash);
- if (b) {
- appeal.setStatus(3);
- appeal.setLastAmount(new BigDecimal("0.0001"));
-
- // 表示这笔归集转账已经成功
- // 更新状态
- memberCoinChargeDao.updateById(appeal);
- }
- }
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/UsdtService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/UsdtService.java
deleted file mode 100644
index bfb5074..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/UsdtService.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang3.StringUtils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-
-
-public class UsdtService {
-// public static void main(String[] args) throws IOException {
-// ECKey key = new ECKey();
-// //logger.info("We created a new key:\n" + key);
-// // TEST 网络
-// NetworkParameters params = MainNetParams.get();
-// Address addressFromKey = key.toAddress(params);
-// System.out.println("Public Address generated: " + addressFromKey);
-// //logger.info("Public Address generated: " + addressFromKey);
-// String privateKey = key.getPrivateKeyEncoded(params).toString();
-// System.out.println("Private key is: " + privateKey);
-// //logger.info("Private key is: " + privateKey);
-// //logger.info("Private Hex key is: " + key.getPrivateKeyAsHex());
-// Wallet wallet = new Wallet(TestNet3Params.get());
-// File walletFile = new File("D//:test.wallet");
-// wallet.importKey(key);
-// wallet.saveToFile(walletFile);
-// }
-
- private static UsdtService service = null;
- private final static String RESULT = "result";
- private final static String METHOD_SEND_TO_ADDRESS = "sendtoaddress";
- private final static String METHOD_GET_TRANSACTION = "gettransaction";
- private final static String METHOD_LIST_TRANSACTIONS = "listtransactions";
- private final static String METHOD_GET_BLOCK_COUNT = "getblockcount";
- private final static String METHOD_NEW_ADDRESS = "getnewaddress";
- private final static String METHOD_GET_BALANCE = "getbalance";
- private final static String METHOD_GET_BALANCE_ADDRESS = "getreceivedbyaddress";
- private final static String METHOD_WALLET_PASSPHRASE = "walletpassphrase";
- private final static String METHOD_WALLET_LOCK = "walletlock";
-
- private String url = "http://120.55.86.146:1880";
- private String username = "biyi";
- private String password = "biyi1234";
-
- public static UsdtService getInstance() {
- if (service != null) {
- return service;
- }
- return new UsdtService();
- }
-
- private UsdtService() {
- }
-
- /**
- * 创建BTC钱包 每个账户对应一个地址 方便后续操作
- *
- * @param mId 账户
- * @return
- */
- public static Map<String, String> createWallet(String mId) {
- UsdtService btcService = getInstance();
- // 创建钱包地址
- String address = btcService.getAddress(mId);
- // 私钥
- String privateKey = btcService.dumpprivkey(address);
- Map<String, String> result = new HashMap<String, String>();
- result.put("address", address);
- result.put("privateKey", privateKey);
- return result;
- }
-
- public String getAddress(String label) {
- try {
- JSONObject json = doRequest(METHOD_NEW_ADDRESS, label);
- if (isError(json)) {
- return "";
- }
- return json.getString(RESULT);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- private JSONObject doRequest(String method, Object... params) {
- JSONObject param = new JSONObject();
- param.put("id", System.currentTimeMillis() + "");
- param.put("jsonrpc", "2.0");
- param.put("method", method);
- if (params != null) {
- param.put("params", params);
- }
- String creb = Base64.encodeBase64String((username + ":" + password).getBytes());
- Map<String, String> headers = new HashMap<>(2);
- headers.put("Authorization", "Basic " + creb);
- return JSON.parseObject(HttpUtil.jsonPost(url, headers, param.toJSONString()));
- }
-
- private boolean isError(JSONObject json) {
- if (json == null || (StringUtils.isNotEmpty(json.getString("error")) && json.get("error") != "null")) {
- return true;
- }
- return false;
- }
-
- public String dumpprivkey(String address) {
- try {
- JSONObject obj = doRequest("dumpprivkey", address);
- System.out.println(obj);
- if (!isError(obj)) {
- return obj.getString(RESULT);
- } else {
- return null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 查询给定地址的总收款额(只计算接受的)
- *
- * @param address
- * @return
- */
- public BigDecimal getBalance(String address) {
- try {
- JSONObject json = doRequest("omni_getbalance", address, 31);
- if (!isError(json)) {
- return new BigDecimal(json.getJSONObject(RESULT).get("balance").toString());
- } else {
- return null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- System.out.println("BTC-USDT查询余额失败");
- return null;
- }
-
- }
-
- public String METHOD_GET_BLOCK_COUNT() {
- JSONObject json = doRequest(METHOD_GET_BLOCK_COUNT);
- if (!isError(json)) {
- return json.getString(RESULT);
- } else {
- return null;
- }
- }
-
-
-
-
-
- public static void main(String[] args) {
-
- System.out.println(UsdtService.getInstance().getBalance("1PLCr8A2z7YLEtoPLJdzzqpfb3Ym87UCtt"));
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/blackchain/service/XrpService.java b/src/main/java/com/xcong/excoin/modules/blackchain/service/XrpService.java
deleted file mode 100644
index 781eee7..0000000
--- a/src/main/java/com/xcong/excoin/modules/blackchain/service/XrpService.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.xcong.excoin.modules.blackchain.service;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.text.MessageFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang3.StringUtils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.ripple.core.coretypes.AccountID;
-import com.ripple.core.coretypes.Amount;
-import com.ripple.core.coretypes.uint.UInt32;
-import com.ripple.core.types.known.tx.signed.SignedTransaction;
-import com.ripple.core.types.known.tx.txns.Payment;
-import com.xcong.excoin.modules.blackchain.model.XrpTransResult;
-
-public class XrpService {
-
- /**
- * 平台钱包地址
- */
- public final static String ACCOUNT="rKMGEyjXErL2dx9ck5QXFJVH8onSfHF5gn";
- /**
- * 官方接口地址
- */
- private static String getUrl = "https://data.ripple.com";
- private String postUrl = "https://s1.ripple.com:51234";
-
- /**
- * 结果类型
- */
- private final static String TES_SUCCESS = "tesSUCCESS";
-
-
-
-
-
- /**
- * start YYYY-MM-DDThh:mm:ssZ String - Timestamp Start time of query range. The default is the
- * earliest date available.
- * end String - Timestamp End time of query range. The
- * default is the current date.
- * min_sequence String Minimum sequence number to
- * query.
- * max_sequence String Max sequence number to query.
- * type String Restrict results to a specified transaction type.
- * result String Restrict results to a specified transaction result.
- * binary Boolean Return results in binary format.
- * descending Boolean If true, return results in reverse chronological order.The default is false.
- * limit Integer Maximum results per page. The default is 20. Cannot be more than 1,000.
- * marker String Pagination key from previously
- * returned response.
- *
- * https://github.com/ripple/rippled-historical-database
- * 接口文档:https://xrpl.org/data-api.html#get-account
- */
- public static XrpTransResult getTransactions(Date start) {
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
- String startTime = dateFormat.format(start);
- String url ="https://data.ripple.com/v2/accounts/"+ACCOUNT+"/transactions?type=Payment&result=tesSUCCESS&limit=100&start="+startTime;
- // 十分钟查一次 每次100条
- String result = HttpUtil.get(url);
- try {
- JSONObject json = JSONObject.parseObject(result);
- XrpTransResult res = json.toJavaObject(XrpTransResult.class);
- return res;
- }catch(Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/controller/CoinController.java b/src/main/java/com/xcong/excoin/modules/coin/controller/CoinController.java
deleted file mode 100644
index 64df9f2..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/controller/CoinController.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package com.xcong.excoin.modules.coin.controller;
-
-import java.math.BigDecimal;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-import com.xcong.excoin.modules.coin.parameter.vo.AllWalletCoinVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberAccountMoneyChangeInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberAgentIntoInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletAgentInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletCoinInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletCoinVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletContractInfoVo;
-
-import io.swagger.annotations.*;
-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;
-
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.coin.parameter.dto.RecordsPageDto;
-import com.xcong.excoin.modules.coin.parameter.dto.TransferOfBalanceDto;
-import com.xcong.excoin.modules.coin.parameter.dto.TransferOfBalanceFromAgentDto;
-import com.xcong.excoin.modules.coin.service.CoinService;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@Api(value = "会员资产接口", tags = "会员资产接口")
-@RestController
-@RequestMapping(value = "/api/walletCoin")
-public class CoinController {
-
- @Resource
- private CoinService coinService;
-
- /**
- * 获取我的总资产
- * @return
- */
- @ApiOperation(value = "获取我的总资产", notes = "获取我的总资产")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = AllWalletCoinVo.class)})
- @GetMapping(value = "/getAllWalletCoin")
- public Result getAllWalletCoin() {
- return coinService.getAllWalletCoin();
- }
- /**
- * 获取我的币币资产信息
- * @return
- */
- @ApiOperation(value = "获取我的币币账户信息", notes = "获取我的币币账户信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberWalletCoinVo.class)})
- @GetMapping(value = "/getWalletCoin")
- public Result getWalletCoin() {
- return coinService.getWalletCoin();
- }
-
- /**
- * 获取币币账户某个币种信息
- * @return
- */
- @ApiOperation(value="获取币币账户某个币种信息", notes="获取币币账户某个币种信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberWalletCoinInfoVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query")
- })
- @GetMapping(value = "/getWalletCoinBySymbol")
- public Result getWalletCoinBySymbol(String symbol) {
- return coinService.getWalletCoinBySymbol(symbol);
- }
-
- /**
- * --todo
- * 获取我的合约资产信息
- * @return
- */
- @ApiOperation(value="获取我的合约账户信息", notes="获取我的合约账户信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberWalletContractInfoVo.class)})
- @GetMapping(value="/getWalletContractById")
- public Result getWalletContractById() {
- return coinService.getWalletContractById();
- }
-
- /**
- * 查询合约账户里面的可用资产余额
- * @return
- */
- @ApiOperation(value="查询合约账户里面的可用资产余额", notes="查询合约账户里面的可用资产余额")
- @GetMapping(value="/findWalletContractBySymbol")
- public Result findWalletContractBySymbol() {
- return coinService.findWalletContractBySymbol();
- }
-
- /**
- * 查询币币账户里面的可用资产余额
- * @return
- */
- @ApiOperation(value="查询币币账户里面的可用资产余额", notes="查询币币账户里面的可用资产余额")
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query")
- })
- @GetMapping(value="/findWalletCoinBySymbol")
- public Result findWalletCoinBysymbol(String symbol) {
- return coinService.findWalletCoinBySymbol(symbol);
- }
-
- /**
- * 查询代理账户里面的资产余额
- * @return
- */
- @ApiOperation(value="查询代理账户信息", notes="查询代理账户信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberWalletAgentInfoVo.class)})
- @GetMapping(value="/findWalletAgentBySymbol")
- public Result findWalletAgentBySymbol() {
- return coinService.findWalletAgentBySymbol();
- }
-
- /**
- * 获取币币资产交易记录
- * @return
- */
- @ApiOperation(value="获取币币资产交易记录", notes="获取币币资产交易记录")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberAccountMoneyChangeInfoVo.class)})
- @PostMapping(value="/getWalletCoinRecords")
- public Result getWalletCoinRecords(@RequestBody @Valid RecordsPageDto recordsPageDto) {
- return coinService.getWalletCoinRecords(recordsPageDto);
- }
-
- /**
- * 获取合约资产交易记录
- * @return
- */
- @ApiOperation(value="获取合约资产交易记录", notes="获取合约资产交易记录")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberAccountMoneyChangeInfoVo.class)})
- @PostMapping(value="/getWalletContractRecords")
- public Result getWalletContractRecords(@RequestBody @Valid RecordsPageDto recordsPageDto) {
- return coinService.getWalletContractRecords(recordsPageDto);
- }
-
- /**
- * 获取代理资产交易记录
- * @return
- */
- @ApiOperation(value="获取代理资产交易记录", notes="获取代理资产交易记录")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberAccountMoneyChangeInfoVo.class)})
- @PostMapping(value="/getWalletAgentRecords")
- public Result getWalletAgentRecords(@RequestBody @Valid RecordsPageDto recordsPageDto) {
- return coinService.getWalletAgentRecords(recordsPageDto);
- }
-
- /**
- * 获取代理资产佣金入账
- * @return
- */
- @ApiOperation(value="获取代理资产佣金入账", notes="获取代理资产佣金入账")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberAgentIntoInfoVo.class)})
- @PostMapping(value="/getWalletAgentIntoRecords")
- public Result getWalletAgentIntoRecords(@RequestBody @Valid RecordsPageDto recordsPageDto) {
- return coinService.getWalletAgentIntoRecords(recordsPageDto);
- }
-
- /**
- * 币币账户USDT划转到合约账户
- * @return
- */
- @ApiOperation(value="币币账户USDT划转到合约账户", notes="币币账户USDT划转到合约账户")
- @PostMapping(value="/coinWalletTransferToContract")
- public Result coinWalletTransferToContract(@RequestBody @Valid TransferOfBalanceDto transferOfBalanceDto) {
- BigDecimal balance = transferOfBalanceDto.getBalance();
- String symbol = transferOfBalanceDto.getSymbol();
- return coinService.coinWalletTransferToContract(balance,symbol);
- }
-
- /**
- * 合约账户划转到币币USDT账户
- * @return
- */
- @ApiOperation(value="合约账户划转到币币USDT账户", notes="合约账户划转到币币USDT账户")
- @PostMapping(value="/contractTransferToWalletCoin")
- public Result contractTransferToWalletCoin(@RequestBody @Valid TransferOfBalanceDto transferOfBalanceDto) {
- BigDecimal balance = transferOfBalanceDto.getBalance();
- String symbol = transferOfBalanceDto.getSymbol();
- return coinService.contractTransferToWalletCoin(balance,symbol);
- }
-
- /**
- * 代理账户划转到USDT账户
- * @return
- */
- @ApiOperation(value="代理账户划转到合约或币币USDT账户", notes="代理账户划转到合约或币币USDT账户")
- @PostMapping(value="/agentTransferToWalletCoin")
- public Result agentTransferToWalletCoin(@RequestBody @Valid TransferOfBalanceFromAgentDto transferOfBalanceFromAgentDto) {
- BigDecimal balance = transferOfBalanceFromAgentDto.getBalance();
- Integer transfertype = transferOfBalanceFromAgentDto.getTransfertype();
- return coinService.agentTransferToWalletCoin(balance,transfertype);
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/controller/OrderCoinController.java b/src/main/java/com/xcong/excoin/modules/coin/controller/OrderCoinController.java
deleted file mode 100644
index f9f4ece..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/controller/OrderCoinController.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package com.xcong.excoin.modules.coin.controller;
-
-import java.math.BigDecimal;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-import org.springframework.validation.annotation.Validated;
-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;
-
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.coin.parameter.dto.CancelEntrustWalletCoinOrderDto;
-import com.xcong.excoin.modules.coin.parameter.dto.FindAllWalletCoinOrderDto;
-import com.xcong.excoin.modules.coin.parameter.dto.FindCollectDto;
-import com.xcong.excoin.modules.coin.parameter.dto.SubmitSalesWalletCoinOrderDto;
-import com.xcong.excoin.modules.coin.parameter.vo.FindCollectListVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberSelectSymbolsVo;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinDealVo;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinListVo;
-import com.xcong.excoin.modules.coin.parameter.vo.TransactionPageOfWalletCoinVo;
-import com.xcong.excoin.modules.coin.service.OrderCoinService;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@Api(value = "币币交易接口", tags = "币币交易接口")
-@RestController
-@RequestMapping(value = "/api/orderCoin")
-public class OrderCoinController {
-
- @Resource
- OrderCoinService orderCoinService;
-
- /**
- * 进入交易页面
- * @return
- */
- @ApiOperation(value = "进入交易页面", notes = "进入交易页面")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = TransactionPageOfWalletCoinVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query")
- })
- @GetMapping(value = "/enterTransactionPageOfWalletCoin")
- public Result enterTransactionPageOfWalletCoin(String symbol) {
- return orderCoinService.enterTransactionPageOfWalletCoin(symbol);
- }
-
- /**
- * 提交买卖订单
- * @return
- */
- @ApiOperation(value = "提交买卖订单", notes = "提交买卖订单")
- @PostMapping(value="/submitSalesWalletCoinOrder")
- public Result submitSalesWalletCoinOrder(@RequestBody @Valid SubmitSalesWalletCoinOrderDto submitSalesWalletCoinOrderDto) {
- String symbol = submitSalesWalletCoinOrderDto.getSymbol();
- Integer type = submitSalesWalletCoinOrderDto.getType();
- Integer tradeType = submitSalesWalletCoinOrderDto.getTradeType();
- BigDecimal price = submitSalesWalletCoinOrderDto.getPrice();
- BigDecimal amount = submitSalesWalletCoinOrderDto.getAmount();
- return orderCoinService.submitSalesWalletCoinOrder(symbol,type,tradeType,price,amount);
- }
-
- /**
- * 获取委托单数据
- * @return
- */
- @ApiOperation(value = "获取委托单数据", notes = "获取委托单数据")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = OrderWalletCoinListVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query"),
- @ApiImplicitParam(name = "status", value = "状态 1:委托中2:撤单3:已成交", required = true, dataType = "int", paramType="query")
- })
- @GetMapping(value = "/getEntrustWalletCoinOrder")
- public Result getEntrustWalletCoinOrder(String symbol,Integer status) {
- return orderCoinService.getEntrustWalletCoinOrder(symbol,status);
- }
-
- /**
- * 撤销委托订单
- * @return
- */
- @ApiOperation(value = "撤销委托订单", notes = "撤销委托订单")
- @PostMapping(value="/cancelEntrustWalletCoinOrder")
- public Result cancelEntrustWalletCoinOrder(@RequestBody @Valid CancelEntrustWalletCoinOrderDto cancelEntrustWalletCoinOrderDto) {
- String orderId = cancelEntrustWalletCoinOrderDto.getOrderId();
- return orderCoinService.cancelEntrustWalletCoinOrder(orderId);
- }
-
- /**
- * 获取币币交易历史订单信息
- * @return
- */
- @ApiOperation(value = "获取币币交易历史订单信息", notes = "获取币币交易历史订单信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = OrderWalletCoinDealVo.class)})
- @PostMapping(value="/findAllWalletCoinOrder")
- public Result findAllWalletCoinOrder(@RequestBody @Validated FindAllWalletCoinOrderDto findAllWalletCoinOrderDto) {
- return orderCoinService.findAllWalletCoinOrder(findAllWalletCoinOrderDto);
- }
-
- /**
- * 获取一条币币交易历史订单信息
- * @return
- */
- @ApiOperation(value = "获取一条币币交易历史订单信息", notes = "获取一条币币交易历史订单信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = OrderWalletCoinDealVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataType = "Long", paramType="query")
- })
- @GetMapping(value = "/findWalletCoinOrder")
- public Result findWalletCoinOrder(Long orderId) {
- return orderCoinService.findWalletCoinOrder(orderId);
- }
-
- /**
- * 币币自选|取消自选
- * @return
- */
- @ApiOperation(value = "币币自选|取消自选", notes = "币币自选|取消自选")
- @PostMapping(value="/findCollect")
- public Result findCollect(@RequestBody @Valid FindCollectDto findCollectDto) {
- String symbol = findCollectDto.getSymbol();
- Integer type = findCollectDto.getType();
- return orderCoinService.findCollect(symbol,type);
- }
-
- /**
- * 币币是否自选
- * @return
- */
- @ApiOperation(value = "币币是否自选", notes = "币币是否自选")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberSelectSymbolsVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query")
- })
- @GetMapping(value = "/checkIsCollect")
- public Result checkIsCollect(String symbol) {
- return orderCoinService.checkIsCollect(symbol);
- }
-
- /**
- * 已自选的币种
- * @return
- */
- @ApiOperation(value = "已自选的币种", notes = "已自选的币种")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = FindCollectListVo.class)})
- @GetMapping(value = "/findCollectList")
- public Result findCollectList() {
- return orderCoinService.findCollectList();
- }
-
- /**
- * 币种搜索
- * @return
- */
- @ApiOperation(value = "币种搜索", notes = "币种搜索")
- @GetMapping(value = "/searchSymbolResultList")
- public Result searchSymbolResultList() {
- return orderCoinService.searchSymbolResultList();
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/dao/MemberAccountFlowEntityDao.java b/src/main/java/com/xcong/excoin/modules/coin/dao/MemberAccountFlowEntityDao.java
deleted file mode 100644
index 64af089..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/dao/MemberAccountFlowEntityDao.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.xcong.excoin.modules.coin.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.coin.entity.MemberAccountFlowEntity;
-
-public interface MemberAccountFlowEntityDao extends BaseMapper<MemberAccountFlowEntity>{
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/dao/MemberAccountMoneyChangeDao.java b/src/main/java/com/xcong/excoin/modules/coin/dao/MemberAccountMoneyChangeDao.java
deleted file mode 100644
index 2319534..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/dao/MemberAccountMoneyChangeDao.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.xcong.excoin.modules.coin.dao;
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsDealEntity;
-
-public interface MemberAccountMoneyChangeDao extends BaseMapper<MemberAccountMoneyChange>{
-
- List<MemberAccountMoneyChange> selectWalletCoinRecordsByMemIdTypeSymbol(Long memberId);
-
- List<MemberAccountMoneyChange> selectWalletContractRecordsByMemIdTypeSymbol(@Param("symbol")String symbol, @Param("memberId")Long memberId);
-
- List<MemberAccountMoneyChange> selectWalletAgentRecordByMemIdTypeSymbol(@Param("symbol")String symbol, @Param("memberId")Long memberId);
-
- List<MemberAccountMoneyChange> selectWalletAgentIntoRecordsByMemIdTypeSymbol(@Param("memberId")Long memberId);
-
- IPage<MemberAccountMoneyChange> selectWalletCoinRecordsInPage(Page<OrderCoinsDealEntity> page,
- @Param("record") MemberAccountMoneyChange memberAccountMoneyChange);
-
- IPage<MemberAccountMoneyChange> selectWalletContractRecordsInPage(Page<OrderCoinsDealEntity> page,
- @Param("record") MemberAccountMoneyChange memberAccountMoneyChange);
-
- IPage<MemberAccountMoneyChange> selectWalletAgentRecordsInPage(Page<OrderCoinsDealEntity> page,
- @Param("record") MemberAccountMoneyChange memberAccountMoneyChange);
-
- IPage<MemberAccountMoneyChange> selectWalletAgentIntoRecordsByMemIdTypeSymbol(Page<OrderCoinsDealEntity> page,
- @Param("record")MemberAccountMoneyChange memberAccountMoneyChange);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/dao/MemberSelectSymbolsDao.java b/src/main/java/com/xcong/excoin/modules/coin/dao/MemberSelectSymbolsDao.java
deleted file mode 100644
index 4bd7721..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/dao/MemberSelectSymbolsDao.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.coin.dao;
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberSelectSymbolsEntity;
-
-public interface MemberSelectSymbolsDao extends BaseMapper<MemberSelectSymbolsEntity>{
-
- List<MemberSelectSymbolsEntity> selectSymbolByMemIdAndSymbol(@Param("memberId")Long memberId,@Param("symbol")String symbol);
-
- List<MemberSelectSymbolsEntity> selectSymbolByMemId(@Param("memberId")Long memberId);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/dao/OrderCoinDealDao.java b/src/main/java/com/xcong/excoin/modules/coin/dao/OrderCoinDealDao.java
deleted file mode 100644
index ab900b8..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/dao/OrderCoinDealDao.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.modules.coin.dao;
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsDealEntity;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-
-public interface OrderCoinDealDao extends BaseMapper<OrderCoinsDealEntity>{
-
- List<OrderCoinsDealEntity> selectAllWalletCoinOrder(@Param("memberId")Long memberId);
-
- List<OrderCoinsDealEntity> selectAllWalletCoinOrderBySymbol(@Param("memberId")Long memberId,@Param("symbol")String symbol);
-
- OrderCoinsDealEntity selectWalletCoinOrder(@Param("memberId")Long memberId,@Param("orderId")Long orderId);
-
- IPage<OrderCoinsDealEntity> findAllWalletCoinOrderInPage(Page<OrderCoinsDealEntity> page,
- @Param("record") OrderCoinsDealEntity orderCoinsDealEntity);
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/dao/OrderCoinsDao.java b/src/main/java/com/xcong/excoin/modules/coin/dao/OrderCoinsDao.java
deleted file mode 100644
index beed401..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/dao/OrderCoinsDao.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.xcong.excoin.modules.coin.dao;
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsEntity;
-
-public interface OrderCoinsDao extends BaseMapper<OrderCoinsEntity>{
-
- long getOrderCountByToday(@Param("now")String now,@Param("tomorrow") String tomorrow);
-
- List<OrderCoinsEntity> findCoinOrderListByMemberIdAndSysmbol(@Param("memberId")Long memberId,@Param("symbol")String symbol,@Param("status")int status);
-
- OrderCoinsEntity findWalletCoinOrderByOrderNo(@Param("orderNo")String orderNo);
-
- List<OrderCoinsEntity> selectAllEntrustingCoinOrderList();
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/entity/MemberAccountFlowEntity.java b/src/main/java/com/xcong/excoin/modules/coin/entity/MemberAccountFlowEntity.java
deleted file mode 100644
index 396540b..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/entity/MemberAccountFlowEntity.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.xcong.excoin.modules.coin.entity;
-
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-/**
- * 会员账户流水情况
- */
-@Data
-@TableName("member_account_flow")
-public class MemberAccountFlowEntity extends BaseEntity {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * 会员ID
- */
- private Long memberId;
-
- /**
- * 价格
- */
- private BigDecimal price;
-
- /**
- * 用户余额
- */
- private BigDecimal balance;
-
- /**
- * 来源
- */
- private String source;
-
- public static final String SOURCE_BUY = "币币买入";
- public static final String SOURCE_SALE = "币币卖出";
- public static final String SOURCE_CANCEL = "撤销币币委托单";
-
- /**
- * 币种
- */
- private String symbol;
-
- /**
- * 备注
- */
- private String remark;
- public static final String REMARK_BUY = "买入";
- public static final String REMARK_SALE = "卖出";
- public static final String REMARK_CANCEL = "撤销";
- public static final String REMARK_RETURNBALANCE = "返回金额:";
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/entity/MemberAccountMoneyChange.java b/src/main/java/com/xcong/excoin/modules/coin/entity/MemberAccountMoneyChange.java
deleted file mode 100644
index 35f5d7a..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/entity/MemberAccountMoneyChange.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.xcong.excoin.modules.coin.entity;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-
-@Data
-@TableName("member_account_money_change")
-public class MemberAccountMoneyChange extends BaseEntity {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 类型【1:币币资产2:合约资产3:代理资产】
- */
- public static final Integer TYPE_WALLET_COIN = 1;
- public static final Integer TYPE_WALLET_CONTRACT = 2;
- public static final Integer TYPE_WALLET_AGENT = 3;
- /**
- * 状态【0:待审核 1:成功2:失败】
- */
- public static final Integer STATUS_WAIT_INTEGER = 0;
- public static final Integer STATUS_SUCCESS_INTEGER = 1;
- public static final Integer STATUS_FAIL_INTEGER = 2;
-
- private Long memberId;
-
- /**
- * 币种
- */
- private String symbol;
-
- /**
- * 金额
- */
- private BigDecimal amount;
- /**
- * 记录内容
- */
- private String content;
- /**
- * 类型【1:币币资产2:合约资产3:代理资产】
- */
- private int type;
- /**
- * 状态【0:待审核 1:成功2:失败】
- */
- private int status;
- /**
- * 提币ID
- */
- private Long withdrawId;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/entity/OrderCoinsDealEntity.java b/src/main/java/com/xcong/excoin/modules/coin/entity/OrderCoinsDealEntity.java
deleted file mode 100644
index de6f514..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/entity/OrderCoinsDealEntity.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.xcong.excoin.modules.coin.entity;
-
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-
-/**
- * 币币订单成交表
- */
-@Data
-@TableName("coins_order_deal")
-public class OrderCoinsDealEntity extends BaseEntity{
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- /**
- * 会员ID
- */
- private Long memberId;
- /**
- * 订单主表ID
- */
- private Long orderId;
- /**
- * 订单编号
- */
- private String orderNo;
- /**
- * 订单类型 1、买入2、卖出
- */
- private Integer orderType;
- public static final Integer ORDERTYPE_BUY = 1;
- public static final Integer ORDERTYPE_SELL = 2;
- /**
- * 交易类型 1:市价2:限价
- */
- private Integer tradeType;
- public static final Integer TRADETYPE_MARKETPRICE = 1;
- public static final Integer TRADETYPE_FIXEDPRICE = 2;
-
- /**
- * 状态 2:撤单3:已成交
- */
- private Integer orderStatus;
- public static final Integer ORDERSTATUS_CANCEL = 2;
- public static final Integer ORDERSTATUS_DONE = 3;
- /**
- * 币种
- */
- private String symbol;
- /**
- * 数量
- */
- private BigDecimal symbolCnt;
- /**
- * 委托价
- */
- private BigDecimal entrustPrice;
- /**
- * 成交价
- */
- private BigDecimal dealPrice;
- /**
- * 成交金额
- */
- private BigDecimal dealAmount;
- /**
- * 手续费
- */
- private BigDecimal feeAmount;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/entity/OrderCoinsEntity.java b/src/main/java/com/xcong/excoin/modules/coin/entity/OrderCoinsEntity.java
deleted file mode 100644
index 54cadd8..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/entity/OrderCoinsEntity.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.xcong.excoin.modules.coin.entity;
-
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-
-/**
- * 币币订单表
- */
-@Data
-@TableName("coins_order")
-public class OrderCoinsEntity extends BaseEntity{
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * 会员ID
- */
- private Long memberId;
- /**
- * 订单编号
- */
- private String orderNo;
- /**
- * 订单类型 1、买入2、卖出
- */
- private Integer orderType;
- public static final Integer ORDERTYPE_BUY = 1;
- public static final Integer ORDERTYPE_SELL = 2;
-
- /**
- * 币种
- */
- private String symbol;
- /**
- * 市场价
- */
- private BigDecimal markPrice;
- /**
- * 委托量
- */
- private BigDecimal entrustCnt;
- /**
- * 委托价
- */
- private BigDecimal entrustPrice;
- /**
- * 成交量
- */
- private BigDecimal dealCnt;
- /**
- * 成交价
- */
- private BigDecimal dealPrice;
- /**
- * 成交金额
- */
- private BigDecimal dealAmount;
- /**
- * 状态 1:委托中2:撤单3:已成交
- */
- private Integer orderStatus;
- public static final Integer ORDERSTATUS_DODING = 1;
- public static final Integer ORDERSTATUS_CANCEL = 2;
- public static final Integer ORDERSTATUS_DONE = 3;
-
- /**
- * 交易类型 1:市价2:限价
- */
- private Integer tradeType;
- public static final Integer TRADETYPE_MARKETPRICE = 1;
- public static final Integer TRADETYPE_FIXEDPRICE = 2;
-
- /**
- * 手续费
- */
- private BigDecimal feeAmount;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/mapper/MemberAccountMoneyChangeMapper.java b/src/main/java/com/xcong/excoin/modules/coin/mapper/MemberAccountMoneyChangeMapper.java
deleted file mode 100644
index 6ff5422..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/mapper/MemberAccountMoneyChangeMapper.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.modules.coin.mapper;
-
-import java.util.List;
-
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberAccountMoneyChangeInfoVo;
-
-@Mapper
-public abstract class MemberAccountMoneyChangeMapper {
-
- public static final MemberAccountMoneyChangeMapper INSTANCE = Mappers.getMapper(MemberAccountMoneyChangeMapper.class);
-
- public abstract MemberAccountMoneyChangeInfoVo entityToVoOrder(MemberAccountMoneyChange memberAccountMoneyChange);
-
- public abstract List<MemberAccountMoneyChangeInfoVo> orderEntitiesToOrderListVo(List<MemberAccountMoneyChange> memberAccountMoneyChanges);
-
- public abstract Page<MemberAccountMoneyChangeInfoVo> pageEntityToPageVo(IPage<MemberAccountMoneyChange> memberAccountMoneyChanges);
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderCoinsDealMapper.java b/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderCoinsDealMapper.java
deleted file mode 100644
index e2375b2..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderCoinsDealMapper.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.coin.mapper;
-
-import com.xcong.excoin.modules.coin.entity.OrderCoinsDealEntity;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsEntity;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.factory.Mappers;
-
-/**
- * @author wzy
- * @date 2020-07-01
- **/
-@Mapper
-public abstract class OrderCoinsDealMapper {
-
- public static final OrderCoinsDealMapper INSTANCE = Mappers.getMapper(OrderCoinsDealMapper.class);
-
- @Mapping(target = "symbolCnt", source = "entrustCnt")
- public abstract OrderCoinsDealEntity orderToOrderDeal(OrderCoinsEntity orderCoinsEntity);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderWalletCoinDealMapper.java b/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderWalletCoinDealMapper.java
deleted file mode 100644
index ddd13a3..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderWalletCoinDealMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.coin.mapper;
-
-import java.util.List;
-
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsDealEntity;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinDealVo;
-
-@Mapper
-public abstract class OrderWalletCoinDealMapper {
-
- public static final OrderWalletCoinDealMapper INSTANCE = Mappers.getMapper(OrderWalletCoinDealMapper.class);
-
- public abstract OrderWalletCoinDealVo entityToVoOrder(OrderCoinsDealEntity orderCoinsDealEntity);
-
- public abstract List<OrderWalletCoinDealVo> orderEntitiesToOrderListVo(List<OrderCoinsDealEntity> orderEntities);
-
- public abstract Page<OrderWalletCoinDealVo> pageEntityToPageVo(IPage<OrderCoinsDealEntity> orderCoins);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderWalletCoinMapper.java b/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderWalletCoinMapper.java
deleted file mode 100644
index 742896f..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/mapper/OrderWalletCoinMapper.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.coin.mapper;
-
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import com.xcong.excoin.modules.coin.entity.OrderCoinsEntity;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinVo;
-
-@Mapper
-public abstract class OrderWalletCoinMapper {
-
- public static final OrderWalletCoinMapper INSTANCE = Mappers.getMapper(OrderWalletCoinMapper.class);
-
- public abstract OrderWalletCoinVo entityToVo(OrderCoinsEntity orderCoinsEntity);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/CancelEntrustWalletCoinOrderDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/CancelEntrustWalletCoinOrderDto.java
deleted file mode 100644
index 19ff619..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/CancelEntrustWalletCoinOrderDto.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "CancelEntrustWalletCoinOrderDto", description = "撤销委托订单")
-public class CancelEntrustWalletCoinOrderDto {
-
- @NotNull(message = "订单ID不能为空")
- @ApiModelProperty(value = "订单ID", example = "100")
- private String orderId;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/FindAllWalletCoinOrderDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/FindAllWalletCoinOrderDto.java
deleted file mode 100644
index 7990a5d..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/FindAllWalletCoinOrderDto.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "FindAllWalletCoinOrderDto", description = "获取币币交易历史订单信息参数接受类")
-public class FindAllWalletCoinOrderDto {
-
- @NotNull
- @Min(1)
- @ApiModelProperty(value = "第几页", example = "1")
- private int pageNum;
-
- @NotNull
- @ApiModelProperty(value = "每页数量", example = "10")
- private int pageSize;
-
- @NotNull
- @ApiModelProperty(value = "币种", example = "BTC")
- private String symbol;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/FindCollectDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/FindCollectDto.java
deleted file mode 100644
index 5367b10..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/FindCollectDto.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "FindCollectDto", description = "币币自选|取消自选参数接收类")
-public class FindCollectDto {
-
- @NotNull(message = "币种")
- @ApiModelProperty(value = "币种", example = "BTC")
- private String symbol;
-
- @NotNull(message = "币币自选")
- @ApiModelProperty(value = "自选标识1:选中0:未选中", example = "1")
- private Integer type;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/InOrderCoinDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/InOrderCoinDto.java
deleted file mode 100644
index 2a54cf0..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/InOrderCoinDto.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import java.math.BigDecimal;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "InOrderCoinDto", description = "进入交易页面参数接收类")
-public class InOrderCoinDto {
-
- @NotNull(message = "划转金额不能为空")
- @ApiModelProperty(value = "划转金额", example = "100")
- private BigDecimal balance;
-
- @NotNull(message = "币种不能为空")
- @ApiModelProperty(value = "币种", example = "USDT")
- private String symbol;
-
- @NotNull(message = "账户类型不能为空")
- @ApiModelProperty(value = "账户类型", example = "1")
- private Integer transfertype;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/RecordsPageDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/RecordsPageDto.java
deleted file mode 100644
index c1e9fdd..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/RecordsPageDto.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "RecordsPageDto", description = "资产交易记录参数接受类")
-public class RecordsPageDto {
-
- @NotNull
- @Min(1)
- @ApiModelProperty(value = "第几页", example = "1")
- private int pageNum;
-
- @NotNull
- @ApiModelProperty(value = "每页数量", example = "10")
- private int pageSize;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/SubmitSalesWalletCoinOrderDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/SubmitSalesWalletCoinOrderDto.java
deleted file mode 100644
index b15186a..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/SubmitSalesWalletCoinOrderDto.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import java.math.BigDecimal;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "SubmitSalesWalletCoinOrderDto", description = "提交买卖订单参数接收类")
-public class SubmitSalesWalletCoinOrderDto {
-
-
- @NotNull(message = "币种不能为空")
- @ApiModelProperty(value = "币种", example = "BTC")
- private String symbol;
-
- @NotNull(message = "交易类型不能为空")
- @ApiModelProperty(value = "买入卖出类型买入:1,卖出:2", example = "1")
- private Integer type;
-
- @NotNull(message = "交易方式不能为空")
- @ApiModelProperty(value = "市价:1,限价:2", example = "1")
- private Integer tradeType;
-
- @Min(0)
- @NotNull(message = "数量不能为空")
- @ApiModelProperty(value = "数量", example = "100")
- private BigDecimal amount;
-
- @NotNull(message = "建仓价不能为空")
- @ApiModelProperty(value = "建仓价", example = "20.0000")
- private BigDecimal price;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/TransferOfBalanceDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/TransferOfBalanceDto.java
deleted file mode 100644
index e1f9967..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/TransferOfBalanceDto.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import java.math.BigDecimal;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "TransferOfBalanceDto", description = "资金划转参数接收类")
-public class TransferOfBalanceDto {
-
- @NotNull(message = "划转金额不能为空")
- @ApiModelProperty(value = "划转金额", example = "100")
- private BigDecimal balance;
-
- @NotNull(message = "币种不能为空")
- @ApiModelProperty(value = "币种", example = "USDT")
- private String symbol;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/TransferOfBalanceFromAgentDto.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/TransferOfBalanceFromAgentDto.java
deleted file mode 100644
index bd7f8d4..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/dto/TransferOfBalanceFromAgentDto.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.dto;
-
-import java.math.BigDecimal;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-@Data
-@ApiModel(value = "TransferOfBalanceFromAgentDto", description = "资金划转参数接收类")
-public class TransferOfBalanceFromAgentDto {
-
- @NotNull(message = "划转金额不能为空")
- @ApiModelProperty(value = "划转金额", example = "100")
- private BigDecimal balance;
-
- @NotNull(message = "币种不能为空")
- @ApiModelProperty(value = "币种", example = "USDT")
- private String symbol;
-
- @NotNull(message = "账户类型不能为空")
- @ApiModelProperty(value = "转账类型1:转币币,2:转合约", example = "1")
- private Integer transfertype;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/AllWalletCoinVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/AllWalletCoinVo.java
deleted file mode 100644
index d1e4ae2..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/AllWalletCoinVo.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "AllWalletCoinVo", description = "信息返回")
-public class AllWalletCoinVo {
-
- @ApiModelProperty(value = "账户总USDT")
- private BigDecimal totalUsdt;
-
- @ApiModelProperty(value = "账户总RMB")
- private BigDecimal totalCny;
-
- @ApiModelProperty(value = "币币USDT")
- private BigDecimal walletUsdt;
-
- @ApiModelProperty(value = "合约USDT")
- private BigDecimal contractUsdt;
-
- @ApiModelProperty(value = "代理USDT")
- private BigDecimal agentUsdt;
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/FindCollectListVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/FindCollectListVo.java
deleted file mode 100644
index 2d68aad..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/FindCollectListVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "FindCollectListVo", description = "币币是否自选返回")
-public class FindCollectListVo {
-
- @ApiModelProperty(value = "币币自选")
- private List<MemberSelectSymbolsVo> memberSelectSymbolsVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAccountMoneyChangeInfoVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAccountMoneyChangeInfoVo.java
deleted file mode 100644
index 69306a0..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAccountMoneyChangeInfoVo.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberAccountMoneyChangeInfoVo", description = "资产交易记录详情信息返回")
-public class MemberAccountMoneyChangeInfoVo {
-
- /**
- * 币种
- */
- @ApiModelProperty(value = "币种")
- private String symbol;
- /**
- * 金额
- */
- @ApiModelProperty(value = "金额")
- private BigDecimal amount;
- /**
- * 记录内容
- */
- @ApiModelProperty(value = "记录内容")
- private String content;
- /**
- * 类型【1:币币资产2:合约资产3:代理资产】
- */
- @ApiModelProperty(value = "类型【1:币币资产2:合约资产3:代理资产】")
- private int type;
- /**
- * 状态【0:待审核 1:成功2:失败】
- */
- @ApiModelProperty(value = "状态【0:待审核 1:成功2:失败】")
- private int status;
-
- @ApiModelProperty(value = "时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date updateTime;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAccountMoneyChangeVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAccountMoneyChangeVo.java
deleted file mode 100644
index c1de610..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAccountMoneyChangeVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberAccountMoneyChangeVo", description = "资产交易记录信息返回")
-public class MemberAccountMoneyChangeVo {
-
- @ApiModelProperty(value = "资产交易记录详情信息")
- private List<MemberAccountMoneyChangeInfoVo> memberAccountMoneyChangeInfoVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAgentIntoInfoVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAgentIntoInfoVo.java
deleted file mode 100644
index ed7ecbb..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberAgentIntoInfoVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberAgentIntoInfoVo", description = "佣金入账记录信息返回")
-public class MemberAgentIntoInfoVo {
-
- @ApiModelProperty(value = "资产交易记录详情信息")
- private List<MemberAccountMoneyChangeInfoVo> memberAccountMoneyChangeInfoVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberSelectSymbolsVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberSelectSymbolsVo.java
deleted file mode 100644
index d5cc0e2..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberSelectSymbolsVo.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberSelectSymbolsVo", description = "币币是否自选返回")
-public class MemberSelectSymbolsVo {
- /**
- * 会员ID
- */
- @ApiModelProperty(value = "是否自选1:选中0:未选中")
- private Integer isCollect;
- public static final Integer ISCOLLECT_YES = 1;
- public static final Integer ISCOLLECT_NO = 0;
- /**
- * 币种
- */
- @ApiModelProperty(value = "币种")
- private String symbol;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletAgentInfoVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletAgentInfoVo.java
deleted file mode 100644
index 5961d16..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletAgentInfoVo.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberWalletAgentInfoVo", description = "代理账户信息返回")
-public class MemberWalletAgentInfoVo {
-
- /**
- * 总金额
- */
- @ApiModelProperty(value = "总金额")
- private BigDecimal totalBalance;
-
- /**
- * 总人民币金额
- */
- @ApiModelProperty(value = "总人民币金额")
- private BigDecimal totalRMBBalance;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletCoinInfoVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletCoinInfoVo.java
deleted file mode 100644
index 2098c61..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletCoinInfoVo.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-public class MemberWalletCoinInfoVo {
-
- /**
- * 用户Id
- */
- @ApiModelProperty(value = "用户Id")
- private Long memberId;
-
- /**
- * 钱包标识
- */
- @ApiModelProperty(value = "币种名称")
- private String walletCode;
-
- /**
- * 可用余额
- */
- @ApiModelProperty(value = "可用余额")
- private BigDecimal availableBalance;
-
- /**
- * 总金额
- */
- @ApiModelProperty(value = "总金额")
- private BigDecimal totalBalance;
-
- /**
- * 冻结金额
- */
- @ApiModelProperty(value = "冻结金额")
- private BigDecimal frozenBalance;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletCoinVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletCoinVo.java
deleted file mode 100644
index ad0580e..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletCoinVo.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * @author xy
- */
-@Data
-@ApiModel(value = "MemberWalletCoinVo", description = "币币账户信息返回")
-public class MemberWalletCoinVo {
-
- private static final long serialVersionUID = 1L;
-
- @ApiModelProperty(value = "账户总USDT")
- private BigDecimal totalUsdt;
-
- @ApiModelProperty(value = "账户总RMB")
- private BigDecimal totalCny;
-
- @ApiModelProperty(value = "币种详情")
- private List<MemberWalletCoinInfoVo> memberWalletCoinInfoVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletContractInfoVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletContractInfoVo.java
deleted file mode 100644
index 89bcb7a..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/MemberWalletContractInfoVo.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberWalletContractInfoVo", description = "合约账户信息返回")
-public class MemberWalletContractInfoVo {
-
- /**
- * 用户Id
- */
- @ApiModelProperty(value = "用户Id")
- private Long memberId;
-
- /**
- * 可用余额
- */
- @ApiModelProperty(value = "可用余额")
- private BigDecimal availableBalance;
-
- /**
- * 总金额
- */
- @ApiModelProperty(value = "总金额")
- private BigDecimal totalBalance;
-
- /**
- * 总人民币金额
- */
- @ApiModelProperty(value = "总人民币金额")
- private BigDecimal totalRMBBalance;
-
- /**
- * 冻结金额
- */
- @ApiModelProperty(value = "冻结金额")
- private BigDecimal frozenBalance;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinDealListVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinDealListVo.java
deleted file mode 100644
index da1059f..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinDealListVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "OrderWalletCoinDealListVo", description = "币币交易历史订单信息返回")
-public class OrderWalletCoinDealListVo {
-
- @ApiModelProperty(value = "历史订单详情")
- private List<OrderWalletCoinDealVo> orderWalletCoinDealVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinDealVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinDealVo.java
deleted file mode 100644
index 0b5d4a7..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinDealVo.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "OrderWalletCoinDealVo", description = "历史订单详情")
-public class OrderWalletCoinDealVo {
- /**
- * 会员ID
- */
- @ApiModelProperty(value = "会员ID")
- private Long memberId;
- /**
- * 订单主表ID
- */
- @ApiModelProperty(value = "订单主表ID")
- private Long orderId;
- /**
- * 订单编号
- */
- @ApiModelProperty(value = "订单编号")
- private String orderNo;
- /**
- * 订单类型 1、买入2、卖出
- */
- @ApiModelProperty(value = "订单类型 1、买入2、卖出")
- private Integer orderType;
- /**
- * 交易类型 1:市价2:限价
- */
- @ApiModelProperty(value = "交易类型 1:市价2:限价")
- private Integer tradeType;
- /**
- * 币种
- */
- @ApiModelProperty(value = "币种")
- private String symbol;
- /**
- * 数量
- */
- @ApiModelProperty(value = "数量")
- private BigDecimal symbolCnt;
- /**
- * 委托价
- */
- @ApiModelProperty(value = "委托价")
- private BigDecimal entrustPrice;
- /**
- * 成交价
- */
- @ApiModelProperty(value = "成交价")
- private BigDecimal dealPrice;
- /**
- * 成交金额
- */
- @ApiModelProperty(value = "成交金额")
- private BigDecimal dealAmount;
- /**
- * 状态 2:撤单3:已成交
- */
- @ApiModelProperty(value = "状态 2:撤单3:已成交")
- private Integer orderStatus;
-
- /**
- * 手续费
- */
- @ApiModelProperty(value = "手续费")
- private BigDecimal feeAmount;
-
- @ApiModelProperty(value = "时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date updateTime;
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinListVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinListVo.java
deleted file mode 100644
index f85f3ee..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinListVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "OrderWalletCoinListVo", description = "委托单返回")
-public class OrderWalletCoinListVo {
-
- @ApiModelProperty(value = "委托单")
- private List<OrderWalletCoinVo> orderWalletCoinVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinVo.java
deleted file mode 100644
index 8a6f509..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/OrderWalletCoinVo.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "OrderWalletCoinVo", description = "订单详情")
-public class OrderWalletCoinVo {
- /**
- * 订单ID
- */
- @ApiModelProperty(value = "ID")
- private Long id;
- /**
- * 订单编号
- */
- @ApiModelProperty(value = "订单编号")
- private String orderNo;
- /**
- * 币种
- */
- @ApiModelProperty(value = "币种")
- private String symbol;
-
- /**
- * 订单类型 1、买入2、卖出
- */
- @ApiModelProperty(value = "订单类型")
- private Integer orderType;
- /**
- * 市场价
- */
- @ApiModelProperty(value = "市场价")
- private BigDecimal markPrice;
- /**
- * 委托量
- */
- @ApiModelProperty(value = "委托量")
- private BigDecimal entrustCnt;
- /**
- * 委托价
- */
- @ApiModelProperty(value = "委托价")
- private BigDecimal entrustPrice;
- /**
- * 成交量
- */
- @ApiModelProperty(value = "成交量")
- private BigDecimal dealCnt;
- /**
- * 成交价
- */
- @ApiModelProperty(value = "成交价")
- private BigDecimal dealPrice;
- /**
- * 成交金额
- */
- @ApiModelProperty(value = "成交金额")
- private BigDecimal dealAmount;
- /**
- * 手续费
- */
- @ApiModelProperty(value = "手续费")
- private BigDecimal feeAmount;
-
- @ApiModelProperty(value = "时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date updateTime;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/TransactionPageOfWalletCoinVo.java b/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/TransactionPageOfWalletCoinVo.java
deleted file mode 100644
index ec1ceb3..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/parameter/vo/TransactionPageOfWalletCoinVo.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.xcong.excoin.modules.coin.parameter.vo;
-
-import java.math.BigDecimal;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "TransactionPageOfWalletCoinVo", description = "进入交易页面返回")
-public class TransactionPageOfWalletCoinVo {
- /**
- * 是否自选
- */
- @ApiModelProperty(value = "是否自选")
- private Integer isCollect;
- public static final Integer ISCOLLECT_YES = 1;
- public static final Integer ISCOLLECT_NO = 0;
- /**
- * 点差
- */
- @ApiModelProperty(value = "点差")
- private BigDecimal spread;
- /**
- * 币种
- */
- @ApiModelProperty(value = "币种")
- private String symbol;
- /**
- * 买入卖出类型
- */
- @ApiModelProperty(value = "买入卖出类型")
- private String type;
- /**
- * 手续费
- */
- @ApiModelProperty(value = "手续费率")
- private BigDecimal feeRatio;
- /**
- * 用户可用金额
- */
- @ApiModelProperty(value = "买入用户可用金额")
- private BigDecimal availableBalanceBuy;
-
- /**
- * 用户可用金额
- */
- @ApiModelProperty(value = "卖出用户可用金额")
- private BigDecimal availableBalanceSell;
- /**
- * 当前价
- */
- @ApiModelProperty(value = "当前价")
- private BigDecimal currentPrice;
- /**
- * 比例
- */
- @ApiModelProperty(value = "比例")
- private BigDecimal cnyUsdt;
- /**
- * 换算成人民币之后的价格
- */
- @ApiModelProperty(value = "换算成人民币之后的价格")
- private BigDecimal currentPriceCny;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/service/BlockCoinService.java b/src/main/java/com/xcong/excoin/modules/coin/service/BlockCoinService.java
deleted file mode 100644
index e617f0a..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/service/BlockCoinService.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.coin.service;
-
-public interface BlockCoinService {
-
- public void updateEthUsdt();
-
- public void updateEth();
-
- public void updateBtcUsdt();
-
- public void updateBtc();
-
- public void updateEos();
-
- public void updateXrp();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/service/CoinService.java b/src/main/java/com/xcong/excoin/modules/coin/service/CoinService.java
deleted file mode 100644
index 58cdd57..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/service/CoinService.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.xcong.excoin.modules.coin.service;
-
-import java.math.BigDecimal;
-
-import javax.validation.Valid;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.coin.parameter.dto.RecordsPageDto;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-
-public interface CoinService extends IService<MemberWalletCoinEntity>{
-
- public Result getWalletCoin();
-
- public Result getWalletContractById();
-
- public Result coinWalletTransferToContract(BigDecimal balance, String symbol);
-
- public Result contractTransferToWalletCoin(BigDecimal balance, String symbol);
-
- public Result findWalletContractBySymbol();
-
- public Result findWalletCoinBySymbol(String symbol);
-
- public Result agentTransferToWalletCoin(BigDecimal balance, Integer transfertype);
-
- public Result findWalletAgentBySymbol();
-
- public Result getWalletCoinBySymbol(String symbol);
-
- public Result getWalletAgentIntoRecords(@Valid RecordsPageDto recordsPageDto);
-
- public Result getWalletCoinRecords(@Valid RecordsPageDto recordsPageDto);
-
- public Result getWalletContractRecords(@Valid RecordsPageDto recordsPageDto);
-
- public Result getWalletAgentRecords(@Valid RecordsPageDto recordsPageDto);
-
- public Result getAllWalletCoin();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/service/OrderCoinService.java b/src/main/java/com/xcong/excoin/modules/coin/service/OrderCoinService.java
deleted file mode 100644
index a8f2914..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/service/OrderCoinService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.xcong.excoin.modules.coin.service;
-
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsEntity;
-import com.xcong.excoin.modules.coin.parameter.dto.FindAllWalletCoinOrderDto;
-
-public interface OrderCoinService extends IService<OrderCoinsEntity>{
-
- public String generateSimpleSerialno(String userId);
-
- Result enterTransactionPageOfWalletCoin(String symbol);
-
- Result submitSalesWalletCoinOrder(String symbol, Integer type, Integer tradeType, BigDecimal price,
- BigDecimal amount);
-
- public Result getEntrustWalletCoinOrder(String symbol, Integer status);
-
- public Result cancelEntrustWalletCoinOrder(String orderId);
-
- public Result findAllWalletCoinOrder(FindAllWalletCoinOrderDto findAllWalletCoinOrderDto);
-
- public Result findWalletCoinOrder(Long orderId);
-
- public Result findCollect(String symbol, Integer type);
-
- public Result checkIsCollect(String symbol);
-
- public Result findCollectList();
-
- public Result searchSymbolResultList();
-
- public void dealEntrustCoinOrder();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/service/impl/BlockCoinServiceImpl.java b/src/main/java/com/xcong/excoin/modules/coin/service/impl/BlockCoinServiceImpl.java
deleted file mode 100644
index a0ef93b..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/service/impl/BlockCoinServiceImpl.java
+++ /dev/null
@@ -1,431 +0,0 @@
-package com.xcong.excoin.modules.coin.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.StrUtil;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.modules.blackchain.model.EosResult;
-import com.xcong.excoin.modules.blackchain.model.XrpTransResult;
-import com.xcong.excoin.modules.blackchain.model.XrpTransactions;
-import com.xcong.excoin.modules.blackchain.model.XrpTx;
-import com.xcong.excoin.modules.blackchain.service.*;
-import com.xcong.excoin.modules.coin.service.BlockCoinService;
-import com.xcong.excoin.modules.member.dao.MemberCoinAddressDao;
-import com.xcong.excoin.modules.member.dao.MemberCoinChargeDao;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
-import com.xcong.excoin.modules.member.entity.MemberCoinAddressEntity;
-import com.xcong.excoin.modules.member.entity.MemberCoinChargeEntity;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-import com.xcong.excoin.utils.LogRecordUtils;
-import com.xcong.excoin.utils.RedisUtils;
-import com.xcong.excoin.utils.ThreadPoolUtils;
-import com.xcong.excoin.utils.dingtalk.DingTalkUtils;
-import com.xcong.excoin.utils.mail.Sms106Send;
-import com.xcong.excoin.utils.mail.SubMailSend;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-07-02
- **/
-@Slf4j
-@Service
-public class BlockCoinServiceImpl implements BlockCoinService {
-
- @Resource
- private MemberCoinAddressDao memberCoinAddressDao;
- @Resource
- private MemberDao memberDao;
- @Resource
- private MemberCoinChargeDao memberCoinChargeDao;
- @Resource
- private MemberWalletCoinDao memberWalletCoinDao;
-
- @Resource
- private RedisUtils redisUtils;
-
- private final static String EOS_SEQ_KEY="eos_seq_key";
-
- private final static String xrp_update_key = "xrp_update_key";
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void updateEthUsdt() {
- List<MemberCoinAddressEntity> list = memberCoinAddressDao.selectAllBlockAddressBySymbolAndTag(CoinTypeEnum.USDT.name(), "ERC20");
- if (CollUtil.isNotEmpty(list)) {
- EthService ethService = new EthService();
- for (MemberCoinAddressEntity addressEntity : list) {
- String address = addressEntity.getAddress();
- Long memberId = addressEntity.getMemberId();
-
- if (StrUtil.isBlank(address)) {
- continue;
- }
-
- BigDecimal balance = ethService.tokenGetBalance(address);
- if (balance != null && balance.compareTo(new BigDecimal("0.1")) > 0) {
- balance = balance.setScale(8, RoundingMode.CEILING);
-
- BigDecimal early = BigDecimal.ZERO;
- MemberCoinChargeEntity chargeEntity = memberCoinChargeDao.selectNewestChargeRecord(memberId, CoinTypeEnum.USDT.name(), "ERC20");
- if (chargeEntity != null) {
- BigDecimal lastAmount = chargeEntity.getLastAmount();
- if (lastAmount != null) {
- early = lastAmount;
- }
- }
-
- MemberWalletCoinEntity walletCoinEntity = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.USDT.name());
- if (walletCoinEntity == null) {
- continue;
- }
-
- if (balance.compareTo(early) > 0) {
- BigDecimal newBalance = balance.subtract(early);
- memberWalletCoinDao.updateBlockBalance(walletCoinEntity.getId(), newBalance, balance, 0);
-
- String orderNo = insertCoinCharge(address, memberId, newBalance, CoinTypeEnum.USDT.name(), "ERC20", balance);
- // 插入财务记录
- LogRecordUtils.insertMemberAccountMoneyChange(memberId, "转入", newBalance, CoinTypeEnum.USDT.name(), 1, 1);
-
- ThreadPoolUtils.sendDingTalk(5);
- MemberEntity member = memberDao.selectById(memberId);
- if (StrUtil.isNotBlank(member.getPhone())) {
- String amount = newBalance.toPlainString() + "USDT-ERC20";
- Sms106Send.sendRechargeMsg(member.getPhone(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- } else {
- SubMailSend.sendRechargeMail(member.getEmail(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- }
- }
- }
- }
- }
- }
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void updateEth() {
- List<MemberCoinAddressEntity> list = memberCoinAddressDao.selectAllBlockAddressBySymbol(CoinTypeEnum.ETH.name());
- if (CollUtil.isNotEmpty(list)) {
- for (MemberCoinAddressEntity coinAddressEntity : list) {
- String address = coinAddressEntity.getAddress();
- Long memberId = coinAddressEntity.getMemberId();
-
- BigDecimal balance = EthService.getEthBlance(address);
- if (balance != null && new BigDecimal("0.01").compareTo(balance) < 0) {
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.ETH.name());
-
- if (walletCoin == null) {
- continue;
- }
-
- BigDecimal early = BigDecimal.ZERO;
- MemberCoinChargeEntity coinChargeEntity = memberCoinChargeDao.selectNewestChargeRecord(memberId, CoinTypeEnum.ETH.name(), null);
- if (coinChargeEntity != null) {
- BigDecimal lastAmount = coinChargeEntity.getLastAmount();
- if (lastAmount != null) {
- early = lastAmount;
- }
- }
-
- balance = balance.setScale(8, RoundingMode.CEILING);
- if (balance.compareTo(early) > 0) {
- log.info("#ETH更新:{},{},{}#", memberId, balance, early);
-
- BigDecimal newBalance = balance.subtract(early);
- memberWalletCoinDao.updateBlockBalance(walletCoin.getId(), newBalance, balance, 0);
- String orderNo = insertCoinCharge(address, memberId, newBalance, CoinTypeEnum.ETH.name(), null, balance);
-
- // 插入财务记录
- LogRecordUtils.insertMemberAccountMoneyChange(memberId, "转入", newBalance, CoinTypeEnum.ETH.name(), 1, 1);
-
- ThreadPoolUtils.sendDingTalk(5);
- MemberEntity member = memberDao.selectById(memberId);
- if (StrUtil.isNotBlank(member.getPhone())) {
- String amount = newBalance.toPlainString() + "ETH";
- Sms106Send.sendRechargeMsg(member.getPhone(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- } else {
- SubMailSend.sendRechargeMail(member.getEmail(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- }
- }
- }
- }
- }
- }
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void updateBtcUsdt() {
- List<MemberCoinAddressEntity> list = memberCoinAddressDao.selectAllBlockAddressBySymbolAndTag(CoinTypeEnum.USDT.name(), "OMNI");
- if (CollUtil.isNotEmpty(list)) {
- UsdtService usdtService = UsdtService.getInstance();
-
- for (MemberCoinAddressEntity coinAddressEntity : list) {
- String address = coinAddressEntity.getAddress();
- Long memberId = coinAddressEntity.getMemberId();
-
- BigDecimal balance = usdtService.getBalance(address);
- if (balance != null && balance.compareTo(new BigDecimal("0.1")) > 0) {
- MemberCoinChargeEntity memberCoinChargeEntity = memberCoinChargeDao.selectNewestChargeRecord(memberId, CoinTypeEnum.USDT.name(), "OMNI");
- BigDecimal early = BigDecimal.ZERO;
- if (memberCoinChargeEntity != null) {
- BigDecimal lastAmount = memberCoinChargeEntity.getLastAmount();
- if (lastAmount != null) {
- early = lastAmount;
- }
- }
-
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.USDT.name());
- if (walletCoin == null) {
- continue;
- }
-
- if (balance.compareTo(early) > 0) {
- BigDecimal newBalance = balance.subtract(early);
-
- memberWalletCoinDao.updateBlockBalance(walletCoin.getId(), newBalance, balance, 0);
- String orderNo = insertCoinCharge(address, memberId, newBalance, CoinTypeEnum.USDT.name(), "OMNI", balance);
-
- ThreadPoolUtils.sendDingTalk(5);
- MemberEntity member = memberDao.selectById(memberId);
- if (StrUtil.isNotBlank(member.getPhone())) {
- String amount = newBalance.toPlainString() + "USDT-OMNI";
- Sms106Send.sendRechargeMsg(member.getPhone(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- } else {
- SubMailSend.sendRechargeMail(member.getEmail(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- }
- }
- }
- }
- }
- }
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void updateBtc() {
- List<MemberCoinAddressEntity> list = memberCoinAddressDao.selectAllBlockAddressBySymbol(CoinTypeEnum.BTC.name());
- if (CollUtil.isNotEmpty(list)) {
- BtcService btcService = BtcService.getInstance();
- for (MemberCoinAddressEntity coinAddressEntity : list) {
- String address = coinAddressEntity.getAddress();
- Long memberId = coinAddressEntity.getMemberId();
-
- BigDecimal balance = btcService.getBalance(address);
-
- if (balance != null && balance.compareTo(new BigDecimal("0.00012")) > 0) {
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.BTC.name());
- if (walletCoin == null) {
- continue;
- }
-
- BigDecimal early = BigDecimal.ZERO;
- MemberCoinChargeEntity coinCharge = memberCoinChargeDao.selectNewestChargeRecord(memberId, CoinTypeEnum.BTC.name(), null);
- if (coinCharge != null) {
- BigDecimal lastAmount = coinCharge.getLastAmount();
- if (lastAmount != null) {
- early = lastAmount;
- }
- }
-
- if (balance.compareTo(early) > 0) {
- log.info("#btc同步:{}, {}, {}#", memberId, balance, early);
- BigDecimal newBalance = balance.subtract(early);
- memberWalletCoinDao.updateBlockBalance(walletCoin.getId(), newBalance, balance, 0);
-
- String orderNo = insertCoinCharge(address, memberId, newBalance, CoinTypeEnum.BTC.name(), null, balance);
- LogRecordUtils.insertMemberAccountMoneyChange(memberId, "转入", newBalance, CoinTypeEnum.BTC.name(), 1, 1);
-
- ThreadPoolUtils.sendDingTalk(5);
- MemberEntity member = memberDao.selectById(memberId);
- if (StrUtil.isNotBlank(member.getPhone())) {
- String amount = newBalance.toPlainString() + "BTC";
- Sms106Send.sendRechargeMsg(member.getPhone(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- } else {
- SubMailSend.sendRechargeMail(member.getEmail(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- }
- }
- }
- }
- }
- }
-
- @Override
- public void updateEos() {
- // 获取上次读取的序号
- int pos= 0;
- //每次获取的条数
- int offset = 10;
-
- String eosSeq = redisUtils.getString(EOS_SEQ_KEY);
- if(StringUtils.isNotBlank(eosSeq)){
- pos = Integer.valueOf(eosSeq);
- }
- // 记录最大的seq
- int seq = pos;
- List<EosResult> actions = EosService.getActions(pos, offset);
- if(CollectionUtils.isNotEmpty(actions)){
- for(EosResult eosResult:actions){
- String to = eosResult.getTo();
- Integer accountActionSeq = eosResult.getAccountActionSeq();
- if(accountActionSeq>seq){
- seq = accountActionSeq;
- }
- if(!EosService.ACCOUNT.equals(to)){
- // 判断是否是收款
- continue;
- }
- // 处理收款
- String quantity = eosResult.getQuantity();
- String memo = eosResult.getMemo();
- if(StringUtils.isBlank(memo)){
- // 没有标记的跳过
- continue;
- }
- if(StringUtils.isNotBlank(quantity)){
- // 转账额
- String amountStr = quantity.split("")[0];
- BigDecimal amount = new BigDecimal(amountStr);
- List<MemberCoinAddressEntity> memberCoinAddress = memberCoinAddressDao.selectAllBlockAddressBySymbolAndTag(CoinTypeEnum.EOS.name(), memo);
- if(CollectionUtils.isNotEmpty(memberCoinAddress)){
- MemberCoinAddressEntity memberCoinAddressEntity = memberCoinAddress.get(0);
- // 用户ID
- Long memberId = memberCoinAddressEntity.getMemberId();
- MemberWalletCoinEntity memberWalletCoinEntity = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.EOS.name());
- if(memberCoinAddressEntity!=null){
- memberWalletCoinDao.updateBlockBalance(memberWalletCoinEntity.getId(),amount,BigDecimal.ZERO,0);
- // 添加冲币记录
- String orderNo = insertCoinCharge(EosService.ACCOUNT,memberId,amount,CoinTypeEnum.EOS.name(),memo,BigDecimal.ZERO);
- LogRecordUtils.insertMemberAccountMoneyChange(memberId, "转入", amount, CoinTypeEnum.EOS.name(), 1, 1);
-
- ThreadPoolUtils.sendDingTalk(5);
- MemberEntity member = memberDao.selectById(memberId);
- if (StrUtil.isNotBlank(member.getPhone())) {
- //String amountEos = amountStr + "EOS";
- Sms106Send.sendRechargeMsg(member.getPhone(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- } else {
- SubMailSend.sendRechargeMail(member.getEmail(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- }
- }
- }
- }
- }
- }
- // 最后更新seq 即下次查询的起始位置 在本次最大的基础上加一
- if(seq>0 && seq>pos){
- redisUtils.set(EOS_SEQ_KEY,seq+1);
- }
- }
-
- public void updateXrp() {
- // 首先去查redis上的上次同步时间
- Object lastUpdateTime = redisUtils.get(xrp_update_key);
- SimpleDateFormat format = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
- Date start =null;
- if(lastUpdateTime==null) {
- // 没有 说明是第一次同步 此时从第一天开始同步2020 0716开始
- try {
- start = format.parse("2020-07-16 12:00:00");
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }else {
- // 有上次时间
- try {
- start = format.parse(lastUpdateTime.toString());
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }
-
- // 去查询上次同步时间后的所有记录
- XrpTransResult result = XrpService.getTransactions(start);
- // 写入本次更新时间
- String updateTime = format.format(new Date());
- redisUtils.set(xrp_update_key, updateTime);
- // 判断有无
- List<XrpTransactions> list = result.getTransactions();
- if(CollectionUtils.isNotEmpty(list)) {
- // 不为空 说明有转入记录
- for(XrpTransactions item:list) {
- XrpTx data = item.getTx();
- Integer amountOld = data.getAmount();
- // 除以1000000
- BigDecimal amount = new BigDecimal(amountOld).divide(new BigDecimal(1000000));
- Integer memoInt = data.getDestinationTag();
- // 没有标签直接返回
- if(memoInt==null){
- continue;
- }
- String memo = memoInt.toString();
- String destination = data.getDestination();
- // 判断收款人是不是系统账号
- if(!XrpService.ACCOUNT.equals(destination)){
- continue;
- }
- List<MemberCoinAddressEntity> memberCoinAddress = memberCoinAddressDao.selectAllBlockAddressBySymbolAndTag(CoinTypeEnum.XRP.name(), memo);
- if(CollectionUtils.isNotEmpty(memberCoinAddress)){
- MemberCoinAddressEntity memberCoinAddressEntity = memberCoinAddress.get(0);
- // 用户ID
- Long memberId = memberCoinAddressEntity.getMemberId();
- MemberWalletCoinEntity memberWalletCoinEntity = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.XRP.name());
- if(memberCoinAddressEntity!=null){
- memberWalletCoinDao.updateBlockBalance(memberWalletCoinEntity.getId(),amount,BigDecimal.ZERO,0);
- // 添加冲币记录
- String orderNo = insertCoinCharge(XrpService.ACCOUNT,memberId,amount,CoinTypeEnum.XRP.name(),memo,BigDecimal.ZERO);
- LogRecordUtils.insertMemberAccountMoneyChange(memberId, "转入", amount, CoinTypeEnum.XRP.name(), 1, 1);
-
- ThreadPoolUtils.sendDingTalk(5);
- MemberEntity member = memberDao.selectById(memberId);
- if (StrUtil.isNotBlank(member.getPhone())) {
- //String amountEos = amount + "XRP";
- Sms106Send.sendRechargeMsg(member.getPhone(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- } else {
- SubMailSend.sendRechargeMail(member.getEmail(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo);
- }
- }
- }
-
- }
- }
-
- }
-
- private String generateNo() {
- // 生成订单号
- Long timestamp = System.currentTimeMillis();
- // 随机数
- int random = (int) (Math.random() * 10);
- return String.valueOf(timestamp).substring(2) + random;
- }
-
- public String insertCoinCharge(String address, Long memberId, BigDecimal newBalance, String symbol, String tag, BigDecimal lastAmount) {
- MemberCoinChargeEntity memberCoinChargeEntity = new MemberCoinChargeEntity();
- memberCoinChargeEntity.setAddress(address);
- memberCoinChargeEntity.setMemberId(memberId);
- memberCoinChargeEntity.setAmount(newBalance);
- memberCoinChargeEntity.setSymbol(symbol);
- memberCoinChargeEntity.setTag(tag);
- memberCoinChargeEntity.setStatus(1);
- memberCoinChargeEntity.setLastAmount(lastAmount);
- String orderNo = generateNo();
- memberCoinChargeEntity.setOrderCode(orderNo);
- memberCoinChargeDao.insert(memberCoinChargeEntity);
- return orderNo;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/service/impl/CoinServiceImpl.java b/src/main/java/com/xcong/excoin/modules/coin/service/impl/CoinServiceImpl.java
deleted file mode 100644
index e7ddaae..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/service/impl/CoinServiceImpl.java
+++ /dev/null
@@ -1,577 +0,0 @@
-package com.xcong.excoin.modules.coin.service.impl;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-import com.xcong.excoin.modules.platform.entity.PlatformCnyUsdtExchangeEntity;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.common.enumerates.MemberWalletCoinEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.coin.dao.MemberAccountMoneyChangeDao;
-import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsDealEntity;
-import com.xcong.excoin.modules.coin.mapper.MemberAccountMoneyChangeMapper;
-import com.xcong.excoin.modules.coin.parameter.dto.RecordsPageDto;
-import com.xcong.excoin.modules.coin.parameter.vo.AllWalletCoinVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberAccountMoneyChangeInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberAgentIntoInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletAgentInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletCoinInfoVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletCoinVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberWalletContractInfoVo;
-import com.xcong.excoin.modules.coin.service.CoinService;
-import com.xcong.excoin.modules.member.dao.MemberWalletAgentDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
-import com.xcong.excoin.modules.member.entity.MemberWalletAgentEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-import com.xcong.excoin.modules.platform.dao.PlatformCnyUsdtExchangeDao;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import com.xcong.excoin.utils.RedisUtils;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-
-@Service
-public class CoinServiceImpl extends ServiceImpl<MemberWalletCoinDao, MemberWalletCoinEntity> implements CoinService {
-
- //@Resource
- //SymbolsService symbolsService;
- @Resource
- PlatformCnyUsdtExchangeDao cnyUsdtExchangeDao;
- @Resource
- MemberWalletCoinDao memberWalletCoinDao;
- @Resource
- MemberWalletContractDao memberWalletContractDao;
- @Resource
- MemberAccountMoneyChangeDao memberAccountMoneyChangeDao;
- @Resource
- MemberWalletAgentDao memberWalletAgentDao;
- @Resource
- RedisUtils redisUtils;
-
-
- @Override
- public Result getWalletCoin() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- PlatformCnyUsdtExchangeEntity cnyUsdtExchange = cnyUsdtExchangeDao.getCNYAndUSDTOne();
- BigDecimal cnyUsdt = cnyUsdtExchange.getValue();
-
- BigDecimal totalUsdts = BigDecimal.ZERO;
- if (!StrUtil.isEmpty(memberId.toString())) {
-
- List<MemberWalletCoinEntity> memberWalletCoinlist = memberWalletCoinDao.selectMemberWalletCoinsByMemberId(memberId);
- List<MemberWalletCoinInfoVo> memberWalletCoinInfoVolist = new ArrayList<MemberWalletCoinInfoVo>();
-
- if (CollUtil.isNotEmpty(memberWalletCoinlist)) {
- for (MemberWalletCoinEntity memberWalletCoinEntity : memberWalletCoinlist) {
- MemberWalletCoinInfoVo memberWalletCoinInfoVo = new MemberWalletCoinInfoVo();
- memberWalletCoinInfoVo.setAvailableBalance(memberWalletCoinEntity.getAvailableBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinInfoVo.setFrozenBalance(memberWalletCoinEntity.getFrozenBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinInfoVo.setMemberId(memberWalletCoinEntity.getMemberId());
- memberWalletCoinInfoVo.setTotalBalance(memberWalletCoinEntity.getTotalBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinInfoVo.setWalletCode(memberWalletCoinEntity.getWalletCode());
- memberWalletCoinInfoVolist.add(memberWalletCoinInfoVo);
- }
- }
-
- if (CollUtil.isNotEmpty(memberWalletCoinInfoVolist)) {
- for (MemberWalletCoinInfoVo walletCoin : memberWalletCoinInfoVolist) {
- if (MemberWalletCoinEnum.WALLETCOINCODE.getValue().equals(walletCoin.getWalletCode())) {
- BigDecimal totalUsdt = BigDecimal.ZERO;
- totalUsdt = walletCoin.getAvailableBalance().add(walletCoin.getFrozenBalance());
- totalUsdts = totalUsdts.add(totalUsdt);
- BigDecimal totalCny = totalUsdt.multiply(cnyUsdt);
- walletCoin.setTotalBalance(totalCny);
- } else {
- BigDecimal amount = walletCoin.getAvailableBalance().add(walletCoin.getFrozenBalance());
- // 获取最新价
- BigDecimal closePrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(walletCoin.getWalletCode()+"/USDT")));
- BigDecimal totalUsdt = BigDecimal.ZERO;
- //Double closePrice = symbolsService.getCloseSymbolsBySymbolsName(walletCoin.getWalletCode()+"/USDT");
- totalUsdt = totalUsdt.add(amount.multiply(closePrice));
- totalUsdts = totalUsdts.add(totalUsdt);
- walletCoin.setTotalBalance(totalUsdt.multiply(cnyUsdt));
- }
- }
- }
- MemberWalletCoinVo memberWalletCoinVo = new MemberWalletCoinVo();
- memberWalletCoinVo.setTotalUsdt(totalUsdts.setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinVo.setTotalCny(totalUsdts.multiply(cnyUsdt).setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinVo.setMemberWalletCoinInfoVo(memberWalletCoinInfoVolist);
- return Result.ok(memberWalletCoinVo);
- } else {
- List<MemberWalletCoinInfoVo> memberWalletCoinlist = new ArrayList<MemberWalletCoinInfoVo>();
- MemberWalletCoinInfoVo coin = new MemberWalletCoinInfoVo();
- coin.setAvailableBalance(BigDecimal.ZERO);
- coin.setTotalBalance(BigDecimal.ZERO);
- coin.setFrozenBalance(BigDecimal.ZERO);
- coin.setWalletCode(CoinTypeEnum.BTC.toString());
- memberWalletCoinlist.add(coin);
- coin.setWalletCode(CoinTypeEnum.ETH.toString());
- memberWalletCoinlist.add(coin);
- coin.setWalletCode(CoinTypeEnum.LTC.toString());
- memberWalletCoinlist.add(coin);
- coin.setWalletCode(CoinTypeEnum.BCH.toString());
- memberWalletCoinlist.add(coin);
- coin.setWalletCode(CoinTypeEnum.USDT.toString());
- memberWalletCoinlist.add(coin);
- coin.setWalletCode(CoinTypeEnum.EOS.toString());
- memberWalletCoinlist.add(coin);
- coin.setWalletCode(CoinTypeEnum.XRP.toString());
- memberWalletCoinlist.add(coin);
- coin.setWalletCode(CoinTypeEnum.ETC.toString());
- memberWalletCoinlist.add(coin);
-
- MemberWalletCoinVo memberWalletCoinVo = new MemberWalletCoinVo();
- memberWalletCoinVo.setTotalUsdt(totalUsdts.setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinVo.setTotalCny(totalUsdts.multiply(cnyUsdt).setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinVo.setMemberWalletCoinInfoVo(memberWalletCoinlist);
- return Result.ok(memberWalletCoinVo);
- }
- }
-
- @Override
- public Result getWalletCoinBySymbol(String symbol) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, symbol);
- MemberWalletCoinInfoVo memberWalletCoinInfoVo = new MemberWalletCoinInfoVo();
- memberWalletCoinInfoVo.setFrozenBalance(walletCoin.getFrozenBalance());
- memberWalletCoinInfoVo.setAvailableBalance(walletCoin.getAvailableBalance());
- memberWalletCoinInfoVo.setMemberId(memberId);
- memberWalletCoinInfoVo.setWalletCode(symbol);
- if (!StrUtil.isEmpty(memberId.toString())) {
- PlatformCnyUsdtExchangeEntity cnyUsdtExchange = cnyUsdtExchangeDao.getCNYAndUSDTOne();
- BigDecimal cnyUsdt = cnyUsdtExchange.getValue();
- BigDecimal total = walletCoin.getAvailableBalance().add(walletCoin.getFrozenBalance());
-
- if (MemberWalletCoinEnum.WALLETCOINCODE.getValue().equals(walletCoin.getWalletCode())) {
- memberWalletCoinInfoVo.setTotalBalance(total.multiply(cnyUsdt).setScale(4, BigDecimal.ROUND_DOWN));
-
- } else {
- BigDecimal closePrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol+"/USDT")));
- //Double closePrice = symbolsService.getCloseSymbolsBySymbolsName(wallet.getCode()+"/USDT");
- memberWalletCoinInfoVo.setTotalBalance(total.multiply(closePrice).multiply(cnyUsdt).setScale(4, BigDecimal.ROUND_DOWN));
- }
- }
- return Result.ok(memberWalletCoinInfoVo);
- }
-
- @Override
- public Result getWalletContractById() {
-
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- PlatformCnyUsdtExchangeEntity cnyUsdtExchange = cnyUsdtExchangeDao.getCNYAndUSDTOne();
- BigDecimal cnyUsdt = cnyUsdtExchange.getValue();
-
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, walletCode);
- if (ObjectUtil.isEmpty(walletContract)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0001"));
- }
-
- MemberWalletContractInfoVo memberWalletContractInfoVo = new MemberWalletContractInfoVo();
- memberWalletContractInfoVo.setFrozenBalance(walletContract.getFrozenBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletContractInfoVo.setAvailableBalance(walletContract.getAvailableBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletContractInfoVo.setTotalBalance(walletContract.getTotalBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletContractInfoVo.setTotalRMBBalance(walletContract.getTotalBalance().multiply(cnyUsdt).setScale(4, BigDecimal.ROUND_DOWN));
-
- return Result.ok(memberWalletContractInfoVo);
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Result coinWalletTransferToContract(BigDecimal balance, String symbol) {
- if (balance.compareTo(BigDecimal.ZERO) <= 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0004"));
- }
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- if (!StrUtil.isEmpty(memberId.toString())) {
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, walletCode);
- BigDecimal available = walletCoin.getAvailableBalance();
- // 扣币
- BigDecimal total = available.subtract(balance);
- if (total.compareTo(BigDecimal.ZERO) < 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0005"));
- }
- BigDecimal subtract = walletCoin.getTotalBalance().subtract(balance);
- walletCoin.setAvailableBalance(total);
- walletCoin.setTotalBalance(subtract);
- int updateWalletCoinById = memberWalletCoinDao.updateById(walletCoin);
- if (updateWalletCoinById < 1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0096"));
- }
- // 加币
- // 查询合约账户
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, walletCode);
- BigDecimal availableBalance = walletContract.getAvailableBalance();
- BigDecimal add = availableBalance.add(balance);
- walletContract.setAvailableBalance(add);
- BigDecimal totalBalance = walletContract.getTotalBalance();
- BigDecimal totalBigDecimal = totalBalance.add(balance);
- walletContract.setTotalBalance(totalBigDecimal);
- int updateWalletContractById = memberWalletContractDao.updateById(walletContract);
- if (updateWalletContractById < 1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0096"));
- }
- //添加币币资金划转历史记录
- MemberAccountMoneyChange memberAccountRecord = new MemberAccountMoneyChange();
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTTOCONTRACT.getValue());
- memberAccountRecord.setMemberId(memberId);
- memberAccountRecord.setAmount(balance.negate());
- memberAccountRecord.setStatus(MemberAccountMoneyChange.STATUS_SUCCESS_INTEGER);
- memberAccountRecord.setSymbol(MemberWalletCoinEnum.WALLETCOINCODE.getValue());
- memberAccountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_COIN);
- memberAccountMoneyChangeDao.insert(memberAccountRecord);
-
- //添加合约资金划转历史记录
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTFROMWALLETCOIN.getValue());
- memberAccountRecord.setSymbol(MemberWalletCoinEnum.WALLETCOINCODE.getValue());
- memberAccountRecord.setAmount(balance);
- memberAccountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_CONTRACT);
- memberAccountMoneyChangeDao.insert(memberAccountRecord);
- }
- return Result.ok(MessageSourceUtils.getString("member_service_0006"));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Result contractTransferToWalletCoin(BigDecimal balance, String symbol) {
- if (balance.compareTo(BigDecimal.ZERO) <= 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0004"));
- }
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, walletCode);
- BigDecimal availableBalance = walletContract.getAvailableBalance();
- // 扣币
- BigDecimal availableSubtract = availableBalance.subtract(balance);
- if (availableSubtract.compareTo(BigDecimal.ZERO) < 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0007"));
- }
- BigDecimal totalBalance = walletContract.getTotalBalance();
- BigDecimal totalSubtract = totalBalance.subtract(balance);
-
- walletContract.setAvailableBalance(availableSubtract);
- walletContract.setTotalBalance(totalSubtract);
- int updateWalletCoinById = memberWalletContractDao.updateById(walletContract);
- if (updateWalletCoinById < 1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0096"));
- }
- // 加币
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, walletCode);
- BigDecimal walletCoinAvailableBalance = walletCoin.getAvailableBalance();
- BigDecimal CoinAvailableBalance = walletCoinAvailableBalance.add(balance);
- BigDecimal walletCoinTotalBalance = walletCoin.getTotalBalance();
- BigDecimal CoinTotalBalance = walletCoinTotalBalance.add(balance);
-
- walletCoin.setAvailableBalance(CoinAvailableBalance);
- walletCoin.setTotalBalance(CoinTotalBalance);
- int updateById = memberWalletCoinDao.updateById(walletCoin);
- if (updateById < 1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0096"));
- }
-
- //添加资金划转历史记录
- MemberAccountMoneyChange memberAccountRecord = new MemberAccountMoneyChange();
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTTOWALLETCOIN.getValue());
- memberAccountRecord.setMemberId(memberId);
- memberAccountRecord.setAmount(balance.negate());
- memberAccountRecord.setStatus(MemberAccountMoneyChange.STATUS_SUCCESS_INTEGER);
- memberAccountRecord.setSymbol(walletCode);
- memberAccountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_CONTRACT);
- memberAccountMoneyChangeDao.insert(memberAccountRecord);
-
- //添加资金划转历史记录
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTFROMCONTRACT.getValue());
- memberAccountRecord.setSymbol(walletCode);
- memberAccountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_COIN);
- memberAccountRecord.setAmount(balance);
- memberAccountMoneyChangeDao.insert(memberAccountRecord);
- return Result.ok(MessageSourceUtils.getString("member_service_0006"));
- }
-
- @Override
- public Result findWalletContractBySymbol() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, walletCode);
- BigDecimal availableBalance = walletContract.getAvailableBalance().setScale(4, BigDecimal.ROUND_DOWN);
- return Result.ok(availableBalance);
- }
-
- @Override
- public Result findWalletCoinBySymbol(String symbol) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, symbol);
- BigDecimal availableBalance = walletCoin.getAvailableBalance().setScale(4, BigDecimal.ROUND_DOWN);
- return Result.ok(availableBalance);
- }
-
- @Override
- public Result getWalletCoinRecords(RecordsPageDto recordsPageDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- Page<OrderCoinsDealEntity> page = new Page<>(recordsPageDto.getPageNum(), recordsPageDto.getPageSize());
- MemberAccountMoneyChange memberAccountMoneyChange = new MemberAccountMoneyChange();
- memberAccountMoneyChange.setMemberId(memberId);
- IPage<MemberAccountMoneyChange> list = memberAccountMoneyChangeDao.selectWalletCoinRecordsInPage(page, memberAccountMoneyChange);
- Page<MemberAccountMoneyChangeInfoVo> pageEntityToPageVo = MemberAccountMoneyChangeMapper.INSTANCE.pageEntityToPageVo(list);
-
- return Result.ok(pageEntityToPageVo);
- }
-
- @Override
- public Result getWalletContractRecords(RecordsPageDto recordsPageDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- Page<OrderCoinsDealEntity> page = new Page<>(recordsPageDto.getPageNum(), recordsPageDto.getPageSize());
- MemberAccountMoneyChange memberAccountMoneyChange = new MemberAccountMoneyChange();
- memberAccountMoneyChange.setMemberId(memberId);
- IPage<MemberAccountMoneyChange> list = memberAccountMoneyChangeDao.selectWalletContractRecordsInPage(page, memberAccountMoneyChange);
- Page<MemberAccountMoneyChangeInfoVo> pageEntityToPageVo = MemberAccountMoneyChangeMapper.INSTANCE.pageEntityToPageVo(list);
- return Result.ok(pageEntityToPageVo);
- }
-
- @Override
- public Result getWalletAgentRecords(RecordsPageDto recordsPageDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- Page<OrderCoinsDealEntity> page = new Page<>(recordsPageDto.getPageNum(), recordsPageDto.getPageSize());
- MemberAccountMoneyChange memberAccountMoneyChange = new MemberAccountMoneyChange();
- memberAccountMoneyChange.setMemberId(memberId);
- IPage<MemberAccountMoneyChange> list = memberAccountMoneyChangeDao.selectWalletAgentRecordsInPage(page, memberAccountMoneyChange);
- Page<MemberAccountMoneyChangeInfoVo> pageEntityToPageVo = MemberAccountMoneyChangeMapper.INSTANCE.pageEntityToPageVo(list);
-
- return Result.ok(pageEntityToPageVo);
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Result agentTransferToWalletCoin(BigDecimal balance, Integer transfertype) {
- if (balance.compareTo(BigDecimal.ZERO) <= 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0004"));
- }
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- // 扣币
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletAgentEntity walletAgent = memberWalletAgentDao.selectWalletAgentBymIdAndCode(memberId, walletCode);
- BigDecimal availableBalance = walletAgent.getAvailableBalance();
- BigDecimal totalBalance = walletAgent.getTotalBalance();
-
- BigDecimal available = availableBalance.subtract(balance);
- if (available.compareTo(BigDecimal.ZERO) < 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0008"));
- }
- BigDecimal total = totalBalance.subtract(balance);
- if (total.compareTo(BigDecimal.ZERO) < 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0008"));
- }
-
- walletAgent.setAvailableBalance(available);
- walletAgent.setTotalBalance(total);
-
- int i = memberWalletAgentDao.updateById(walletAgent);
- if (i < 1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0095"));
- }
- //添加资金划转历史记录
- MemberAccountMoneyChange memberAccountRecord = new MemberAccountMoneyChange();
- //代理账户转币币
- if (MemberAccountMoneyChange.TYPE_WALLET_COIN.equals(transfertype)) {
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, walletCode);
- BigDecimal walletCoinAvailableBalance = walletCoin.getAvailableBalance();
- BigDecimal walletCoinTotalBalance = walletCoin.getTotalBalance();
-
- walletCoin.setAvailableBalance(walletCoinAvailableBalance.add(balance));
- walletCoin.setTotalBalance(walletCoinTotalBalance.add(balance));
-
- int updateById = memberWalletCoinDao.updateById(walletCoin);
- if (updateById < 1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0095"));
- }
- //添加资金划转历史记录
- memberAccountRecord.setMemberId(memberId);
- memberAccountRecord.setStatus(MemberAccountMoneyChange.STATUS_SUCCESS_INTEGER);
- memberAccountRecord.setSymbol(walletCode);
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTFROMAGENT.getValue());
- memberAccountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_COIN);
- memberAccountRecord.setAmount(balance);
- memberAccountMoneyChangeDao.insert(memberAccountRecord);
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTTOWALLETCOIN.getValue());
-
- } else if (MemberAccountMoneyChange.TYPE_WALLET_CONTRACT.equals(transfertype)) {
- //代理账户转合约
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, walletCode);
- BigDecimal walletContractAvailableBalance = walletContract.getAvailableBalance();
- BigDecimal walletContractTotalBalance = walletContract.getTotalBalance();
-
- walletContract.setAvailableBalance(walletContractAvailableBalance.add(balance));
- walletContract.setTotalBalance(walletContractTotalBalance.add(balance));
-
- int updateById = memberWalletContractDao.updateById(walletContract);
- if (updateById < 1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0095"));
- }
-
- //添加资金划转历史记录
- memberAccountRecord.setMemberId(memberId);
- memberAccountRecord.setStatus(MemberAccountMoneyChange.STATUS_SUCCESS_INTEGER);
- memberAccountRecord.setSymbol(walletCode);
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTFROMAGENT.getValue());
- memberAccountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_CONTRACT);
- memberAccountRecord.setAmount(balance);
- memberAccountMoneyChangeDao.insert(memberAccountRecord);
- memberAccountRecord.setContent(MemberWalletCoinEnum.CONTENTTOCONTRACT.getValue());
- }
- memberAccountRecord.setAmount(balance.negate());
- memberAccountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_AGENT);
- memberAccountMoneyChangeDao.insert(memberAccountRecord);
-
- return Result.ok(MessageSourceUtils.getString("member_service_0006"));
- }
-
- @Override
- public Result findWalletAgentBySymbol() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
-
- MemberWalletAgentEntity walletAgent = memberWalletAgentDao.selectWalletAgentBymIdAndCode(memberId, walletCode);
- BigDecimal availableBalance = walletAgent.getAvailableBalance();
-
- PlatformCnyUsdtExchangeEntity cnyUsdtExchange = cnyUsdtExchangeDao.getCNYAndUSDTOne();
- BigDecimal cnyUsdt = cnyUsdtExchange.getValue();
- BigDecimal multiply = availableBalance.multiply(cnyUsdt);
-
- MemberWalletAgentInfoVo memberWalletAgentInfoVo = new MemberWalletAgentInfoVo();
- memberWalletAgentInfoVo.setTotalBalance(availableBalance.setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletAgentInfoVo.setTotalRMBBalance(multiply.setScale(4, BigDecimal.ROUND_DOWN));
- return Result.ok(memberWalletAgentInfoVo);
- }
-
- @Override
- public Result getWalletAgentIntoRecords(RecordsPageDto recordsPageDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- Page<OrderCoinsDealEntity> page = new Page<>(recordsPageDto.getPageNum(), recordsPageDto.getPageSize());
- MemberAccountMoneyChange memberAccountMoneyChange = new MemberAccountMoneyChange();
- memberAccountMoneyChange.setMemberId(memberId);
- IPage<MemberAccountMoneyChange> list = memberAccountMoneyChangeDao.selectWalletAgentIntoRecordsByMemIdTypeSymbol(page, memberAccountMoneyChange);
- List<MemberAccountMoneyChange> contractRecordList = list.getRecords();
- List<MemberAccountMoneyChangeInfoVo> arrayList = new ArrayList<>();
- if(CollUtil.isNotEmpty(contractRecordList)) {
- if (ObjectUtil.isNotNull(contractRecordList)) {
- for (MemberAccountMoneyChange memberAccountMoneyChanges : contractRecordList) {
- MemberAccountMoneyChangeInfoVo memberAccountMoneyChangeInfoVo = new MemberAccountMoneyChangeInfoVo();
- memberAccountMoneyChangeInfoVo.setAmount(memberAccountMoneyChanges.getAmount());
- memberAccountMoneyChangeInfoVo.setContent(memberAccountMoneyChanges.getContent());
- memberAccountMoneyChangeInfoVo.setStatus(memberAccountMoneyChanges.getStatus());
- memberAccountMoneyChangeInfoVo.setSymbol(memberAccountMoneyChanges.getSymbol());
- memberAccountMoneyChangeInfoVo.setType(memberAccountMoneyChanges.getType());
- memberAccountMoneyChangeInfoVo.setUpdateTime(memberAccountMoneyChanges.getUpdateTime());
- arrayList.add(memberAccountMoneyChangeInfoVo);
- }
- }
- }
- Page<MemberAccountMoneyChangeInfoVo> pageEntityToPageVo = new Page<>();
- pageEntityToPageVo.setRecords(arrayList);
-
- return Result.ok(pageEntityToPageVo);
- }
-
- @Override
- public Result getAllWalletCoin() {
- //获取【币币】
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- PlatformCnyUsdtExchangeEntity cnyUsdtExchange = cnyUsdtExchangeDao.getCNYAndUSDTOne();
- BigDecimal cnyUsdt = cnyUsdtExchange.getValue();
- AllWalletCoinVo allWalletCoinVo = new AllWalletCoinVo();
-
- BigDecimal totalUsdts = BigDecimal.ZERO;
- if (!StrUtil.isEmpty(memberId.toString())) {
-
- List<MemberWalletCoinEntity> memberWalletCoinlist = memberWalletCoinDao.selectMemberWalletCoinsByMemberId(memberId);
- List<MemberWalletCoinInfoVo> memberWalletCoinInfoVolist = new ArrayList<MemberWalletCoinInfoVo>();
-
- if (CollUtil.isNotEmpty(memberWalletCoinlist)) {
- for (MemberWalletCoinEntity memberWalletCoinEntity : memberWalletCoinlist) {
- MemberWalletCoinInfoVo memberWalletCoinInfoVo = new MemberWalletCoinInfoVo();
- memberWalletCoinInfoVo.setAvailableBalance(memberWalletCoinEntity.getAvailableBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinInfoVo.setFrozenBalance(memberWalletCoinEntity.getFrozenBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinInfoVo.setMemberId(memberWalletCoinEntity.getMemberId());
- memberWalletCoinInfoVo.setTotalBalance(memberWalletCoinEntity.getTotalBalance().setScale(4, BigDecimal.ROUND_DOWN));
- memberWalletCoinInfoVo.setWalletCode(memberWalletCoinEntity.getWalletCode());
- memberWalletCoinInfoVolist.add(memberWalletCoinInfoVo);
- }
- }
-
- if (CollUtil.isNotEmpty(memberWalletCoinInfoVolist)) {
- for (MemberWalletCoinInfoVo walletCoin : memberWalletCoinInfoVolist) {
- if (MemberWalletCoinEnum.WALLETCOINCODE.getValue().equals(walletCoin.getWalletCode())) {
- BigDecimal totalUsdt = BigDecimal.ZERO;
- totalUsdt = walletCoin.getAvailableBalance().add(walletCoin.getFrozenBalance());
- totalUsdts = totalUsdts.add(totalUsdt);
- } else {
- BigDecimal amount = walletCoin.getAvailableBalance().add(walletCoin.getFrozenBalance());
- // 获取最新价
- BigDecimal closePrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(walletCoin.getWalletCode()+"/USDT")));
- BigDecimal totalUsdt = BigDecimal.ZERO;
- totalUsdt = totalUsdt.add(amount.multiply(closePrice));
- totalUsdts = totalUsdts.add(totalUsdt);
- }
- }
- }
- }
- allWalletCoinVo.setWalletUsdt(totalUsdts.setScale(4, BigDecimal.ROUND_DOWN));
- //获取【合约】
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, walletCode);
- if (ObjectUtil.isEmpty(walletContract)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0001"));
- }
- allWalletCoinVo.setContractUsdt(walletContract.getTotalBalance().setScale(4, BigDecimal.ROUND_DOWN));
- totalUsdts = totalUsdts.add(walletContract.getTotalBalance());
- //获取【代理】
- MemberWalletAgentEntity walletAgent = memberWalletAgentDao.selectWalletAgentBymIdAndCode(memberId, walletCode);
- BigDecimal availableBalance = walletAgent.getAvailableBalance();
- allWalletCoinVo.setAgentUsdt(availableBalance.setScale(4, BigDecimal.ROUND_DOWN));
- totalUsdts = totalUsdts.add(availableBalance);
-
- allWalletCoinVo.setTotalUsdt(totalUsdts.setScale(4, BigDecimal.ROUND_DOWN));
- allWalletCoinVo.setTotalCny(totalUsdts.multiply(cnyUsdt).setScale(4, BigDecimal.ROUND_DOWN));
- return Result.ok(allWalletCoinVo);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/coin/service/impl/OrderCoinServiceImpl.java b/src/main/java/com/xcong/excoin/modules/coin/service/impl/OrderCoinServiceImpl.java
deleted file mode 100644
index c96299f..0000000
--- a/src/main/java/com/xcong/excoin/modules/coin/service/impl/OrderCoinServiceImpl.java
+++ /dev/null
@@ -1,641 +0,0 @@
-package com.xcong.excoin.modules.coin.service.impl;
-
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Resource;
-
-import com.xcong.excoin.modules.coin.mapper.OrderCoinsDealMapper;
-import com.xcong.excoin.modules.platform.entity.PlatformCnyUsdtExchangeEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsCoinEntity;
-
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.enumerates.MemberWalletCoinEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.coin.dao.MemberAccountFlowEntityDao;
-import com.xcong.excoin.modules.coin.dao.MemberSelectSymbolsDao;
-import com.xcong.excoin.modules.coin.dao.OrderCoinDealDao;
-import com.xcong.excoin.modules.coin.dao.OrderCoinsDao;
-import com.xcong.excoin.modules.coin.entity.MemberAccountFlowEntity;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsDealEntity;
-import com.xcong.excoin.modules.coin.entity.OrderCoinsEntity;
-import com.xcong.excoin.modules.coin.mapper.OrderWalletCoinDealMapper;
-import com.xcong.excoin.modules.coin.mapper.OrderWalletCoinMapper;
-import com.xcong.excoin.modules.coin.parameter.dto.FindAllWalletCoinOrderDto;
-import com.xcong.excoin.modules.coin.parameter.vo.FindCollectListVo;
-import com.xcong.excoin.modules.coin.parameter.vo.MemberSelectSymbolsVo;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinDealVo;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinListVo;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinVo;
-import com.xcong.excoin.modules.coin.parameter.vo.TransactionPageOfWalletCoinVo;
-import com.xcong.excoin.modules.coin.service.OrderCoinService;
-import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
-import com.xcong.excoin.modules.member.entity.MemberSelectSymbolsEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-import com.xcong.excoin.modules.platform.dao.PlatformCnyUsdtExchangeDao;
-import com.xcong.excoin.modules.platform.dao.PlatformSymbolsCoinDao;
-import com.xcong.excoin.modules.platform.dao.TradeSettingDao;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import com.xcong.excoin.utils.RedisUtils;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.RandomUtil;
-import cn.hutool.core.util.StrUtil;
-
-@Service
-public class OrderCoinServiceImpl extends ServiceImpl<OrderCoinsDao, OrderCoinsEntity> implements OrderCoinService {
-
- @Resource
- TradeSettingDao platformTradeSettingDao;
- @Resource
- MemberWalletCoinDao memberWalletCoinDao;
- @Resource
- MemberSelectSymbolsDao memberSelectSymbolsDao;
- @Resource
- PlatformCnyUsdtExchangeDao cnyUsdtExchangeDao;
- @Resource
- OrderCoinsDao orderCoinsDao;
- @Resource
- OrderCoinDealDao orderCoinDealDao;
- @Resource
- MemberAccountFlowEntityDao memberAccountFlowEntityDao;
- @Resource
- RedisUtils redisUtils;
- @Resource
- PlatformSymbolsCoinDao platformSymbolsCoinDao;
-
- @Override
- public String generateSimpleSerialno(String userId) {
- StringBuilder sb = new StringBuilder();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
- SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd");
- Date now = new Date();
- sb.append(sd.format(now));
- Calendar calendar = new GregorianCalendar();
- calendar.setTime(now);
- calendar.add(calendar.DATE, 1);
- Date nextDate = calendar.getTime();
- if (StrUtil.isNotEmpty(userId)) {
- sb.append(userId);
- }
- sb.append(RandomUtil.randomInt(2));
- long count = orderCoinsDao.getOrderCountByToday(sdf.format(now), sdf.format(nextDate));
- count++;
- int size = 4;
- for (int i = 0; i < size - String.valueOf(count).length(); i++) {
- sb.append("0");
- }
- sb.append(count);
- return sb.toString();
- }
-
- @Override
- public Result enterTransactionPageOfWalletCoin(String symbol) {
- if (StrUtil.isBlank(symbol)) {
- return Result.fail(MessageSourceUtils.getString("order_service_0001"));
- }
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- //获取该币种的币币账户信息
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, symbol);
-
- PlatformTradeSettingEntity tradeSetting = platformTradeSettingDao.findTradeSetting();
- if (ObjectUtil.isEmpty(tradeSetting)) {
- return Result.fail(MessageSourceUtils.getString("order_service_0003"));
- }
- //获取USDT的币币账户信息
- MemberWalletCoinEntity walletCoinUsdt = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId,
- MemberWalletCoinEnum.WALLETCOINCODE.getValue());
-
- BigDecimal closePrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol + "/USDT")));
-
- List<MemberSelectSymbolsEntity> memSymbols = memberSelectSymbolsDao.selectSymbolByMemIdAndSymbol(memberId, symbol);
-
- PlatformCnyUsdtExchangeEntity cnyUsdtExchange = cnyUsdtExchangeDao.getCNYAndUSDTOne();
- BigDecimal cnyUsdt = cnyUsdtExchange.getValue();
- TransactionPageOfWalletCoinVo transactionPageOfWalletCoinVo = new TransactionPageOfWalletCoinVo();
- //是否自选
- if (CollUtil.isEmpty(memSymbols)) {
- transactionPageOfWalletCoinVo.setIsCollect(TransactionPageOfWalletCoinVo.ISCOLLECT_NO);
- } else {
- transactionPageOfWalletCoinVo.setIsCollect(TransactionPageOfWalletCoinVo.ISCOLLECT_YES);
- }
- if (ObjectUtil.isEmpty(walletCoin))
- return Result.fail(MessageSourceUtils.getString("order_service_0003"));
- // 点差
- transactionPageOfWalletCoinVo.setSpread(tradeSetting.getSpread().setScale(4, BigDecimal.ROUND_DOWN));
- // 手续费用率
- transactionPageOfWalletCoinVo.setFeeRatio(tradeSetting.getCoinFeeRatio().setScale(4, BigDecimal.ROUND_DOWN));
- // 用户可用金额
- transactionPageOfWalletCoinVo.setAvailableBalanceBuy(walletCoinUsdt.getAvailableBalance().setScale(4, BigDecimal.ROUND_DOWN));
- transactionPageOfWalletCoinVo.setAvailableBalanceSell(walletCoin.getAvailableBalance().setScale(4, BigDecimal.ROUND_DOWN));
- //当前价
- transactionPageOfWalletCoinVo.setCurrentPrice(closePrice.setScale(4, BigDecimal.ROUND_DOWN));
- //比例
- transactionPageOfWalletCoinVo.setCnyUsdt(cnyUsdt.setScale(4, BigDecimal.ROUND_DOWN));
- //换算成人民币的币种价格
- transactionPageOfWalletCoinVo.setCurrentPriceCny(cnyUsdt.multiply(closePrice).setScale(4, BigDecimal.ROUND_DOWN));
-
- transactionPageOfWalletCoinVo.setSymbol(symbol);
- return Result.ok(transactionPageOfWalletCoinVo);
- }
-
- @Override
- @Transactional
- public Result submitSalesWalletCoinOrder(String symbol, Integer type, Integer tradeType, BigDecimal price, BigDecimal amount) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- BigDecimal nowPriceinBigDecimal = price;
- //查询当前价
- BigDecimal nowPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol + "/USDT")));
-
- // 获取交易管理的杠杠倍率,手续费率等信息,由平台进行设置
- symbol = symbol.toUpperCase();
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, symbol);
- if (ObjectUtil.isEmpty(walletCoin)) {
- return Result.fail(MessageSourceUtils.getString("order_service_0003"));
- }
- // 查询交易设置
- PlatformTradeSettingEntity tradeSetting = platformTradeSettingDao.findTradeSetting();
- if (ObjectUtil.isEmpty(tradeSetting)) {
- return Result.fail(MessageSourceUtils.getString("order_service_0009"));
- }
- // 手续费用(手续费=建仓价X数量X手续费率)
- BigDecimal closingPrice = price.multiply(amount).multiply(tradeSetting.getCoinFeeRatio());
- //总费用 = 成交价*数量+手续费
- BigDecimal totalPayPrice = price.multiply(amount).add(closingPrice);
- BigDecimal totalPayPricCoin = nowPrice.multiply(amount).add(closingPrice);
-
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletCoinEntity walletCoinUsdt = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, walletCode);
- if (OrderCoinsEntity.ORDERTYPE_BUY.equals(type)) {
- //买入,所需总费用跟用户USDT金额进行比较
- BigDecimal availableBalance = walletCoinUsdt.getAvailableBalance();
- if (totalPayPrice.compareTo(availableBalance) > 0 || totalPayPricCoin.compareTo(availableBalance) > 0) {
- return Result.fail(MessageSourceUtils.getString("order_service_0010"));
- }
- } else {
- //卖出,所需总费用跟用户所对应的币种金额进行比较
- BigDecimal availableBalance = walletCoin.getAvailableBalance();
- if (amount.compareTo(availableBalance) > 0) {
- return Result.fail(MessageSourceUtils.getString("order_service_0010"));
- }
- }
-
- // 创建订单
- OrderCoinsEntity order = new OrderCoinsEntity();
- if ((OrderCoinsEntity.TRADETYPE_FIXEDPRICE.equals(tradeType) && type.equals(1) && price.compareTo(nowPrice) < 0)
- || (OrderCoinsEntity.TRADETYPE_FIXEDPRICE.equals(tradeType) && type.equals(2) && price.compareTo(nowPrice) > 0)) {
- // 如果是限价交易直接插入主表数据
- order.setMemberId(memberId);
- order.setOrderNo(generateSimpleSerialno(memberId.toString()));
- order.setOrderType(type);
- order.setSymbol(symbol);
- order.setMarkPrice(nowPrice);
- order.setEntrustCnt(amount);
- order.setEntrustPrice(price);
- order.setDealCnt(amount);
- order.setDealPrice(price);
- order.setDealAmount(totalPayPrice);
- order.setOrderStatus(OrderCoinsEntity.ORDERSTATUS_DODING);
- order.setTradeType(tradeType);
- order.setFeeAmount(closingPrice);
- orderCoinsDao.insert(order);
-
- //更新用户钱包信息
- //冻结相应的资产
- if (OrderCoinsEntity.ORDERTYPE_BUY.equals(type)) {
- //如果是买入,所对应的币种增加,USDT账户减少金额
- BigDecimal availableBalance = walletCoinUsdt.getAvailableBalance().subtract(totalPayPrice);
- BigDecimal frozenBalance = walletCoinUsdt.getFrozenBalance().add(totalPayPrice);
- walletCoinUsdt.setAvailableBalance(availableBalance);
- walletCoinUsdt.setFrozenBalance(frozenBalance);
- memberWalletCoinDao.updateById(walletCoinUsdt);
- } else {
- //如果是卖出,币种减少,USDT增加
- BigDecimal availableBalance = walletCoin.getAvailableBalance().subtract(amount);
- BigDecimal frozenBalance = walletCoin.getFrozenBalance().add(amount);
- walletCoin.setAvailableBalance(availableBalance);
- walletCoin.setFrozenBalance(frozenBalance);
- memberWalletCoinDao.updateById(walletCoin);
- }
- } else {
- //如果是市价交易,主表和附表都需要插入数据
- order.setMemberId(memberId);
- order.setOrderNo(generateSimpleSerialno(memberId.toString()));
- order.setOrderType(type);
- order.setSymbol(symbol);
- order.setMarkPrice(nowPrice);
- order.setEntrustCnt(amount);
- order.setEntrustPrice(price);
- order.setDealCnt(amount);
- if ((OrderCoinsEntity.TRADETYPE_FIXEDPRICE.equals(tradeType) && type.equals(1) && price.compareTo(nowPrice) >= 0)
- || (OrderCoinsEntity.TRADETYPE_FIXEDPRICE.equals(tradeType) && type.equals(2) && price.compareTo(nowPrice) <= 0)) {
- // 手续费用(手续费=建仓价X数量X手续费率)
- closingPrice = nowPrice.multiply(amount).multiply(tradeSetting.getCoinFeeRatio());
- //总费用 = 成交价*数量+手续费
- totalPayPrice = nowPrice.multiply(amount).add(closingPrice);
- price = nowPrice;
- }
- order.setDealPrice(nowPrice);
- order.setDealAmount(totalPayPrice);
- order.setOrderStatus(OrderCoinsEntity.ORDERSTATUS_DONE);
- order.setTradeType(tradeType);
- order.setFeeAmount(closingPrice);
- orderCoinsDao.insert(order);
-
- OrderCoinsDealEntity detail = new OrderCoinsDealEntity();
- detail.setMemberId(memberId);
- detail.setOrderId(order.getId());
- detail.setOrderNo(order.getOrderNo());
- detail.setOrderType(type);
- detail.setTradeType(tradeType);
- detail.setSymbol(symbol);
- detail.setSymbolCnt(amount);
- detail.setEntrustPrice(nowPriceinBigDecimal);
- detail.setDealPrice(nowPrice);
- detail.setDealAmount(totalPayPrice);
- detail.setFeeAmount(closingPrice);
- detail.setOrderStatus(OrderCoinsDealEntity.ORDERSTATUS_DONE);
- orderCoinDealDao.insert(detail);
-
- if (OrderCoinsEntity.ORDERTYPE_BUY.equals(type)) {
- //如果是买入,所对应的币种增加,USDT账户减少金额
- // 更新用户的可用金额
- walletCoin.setAvailableBalance(walletCoin.getAvailableBalance().add(amount));
- memberWalletCoinDao.updateById(walletCoin);
-
- walletCoinUsdt.setAvailableBalance(walletCoinUsdt.getAvailableBalance().subtract(totalPayPrice));
- memberWalletCoinDao.updateById(walletCoinUsdt);
- } else {
- //如果是卖出,币种减少,USDT增加
- walletCoin.setAvailableBalance(walletCoin.getAvailableBalance().subtract(amount));
- memberWalletCoinDao.updateById(walletCoin);
-
- BigDecimal subtract = totalPayPrice.subtract(closingPrice).subtract(closingPrice);
- walletCoinUsdt.setAvailableBalance(walletCoinUsdt.getAvailableBalance().add(subtract));
- memberWalletCoinDao.updateById(walletCoinUsdt);
- }
- }
- // 流水记录
- MemberAccountFlowEntity record = new MemberAccountFlowEntity();
- record.setMemberId(memberId);
- if (OrderCoinsEntity.ORDERTYPE_BUY.equals(type)) {
- record.setPrice(totalPayPrice.setScale(4, BigDecimal.ROUND_DOWN));
- record.setSource(MemberAccountFlowEntity.SOURCE_BUY + symbol);
- record.setRemark(MemberAccountFlowEntity.REMARK_BUY + symbol + ":" + amount);
- } else {
- record.setPrice(totalPayPrice.negate().setScale(4, BigDecimal.ROUND_DOWN));
- record.setSource(MemberAccountFlowEntity.SOURCE_SALE + symbol);
- record.setRemark(MemberAccountFlowEntity.REMARK_SALE + symbol + ":" + amount);
- }
- record.setSymbol(symbol);
- record.setBalance(walletCoinUsdt.getAvailableBalance());
-
- memberAccountFlowEntityDao.insert(record);
-
- return Result.ok(MessageSourceUtils.getString("order_service_0011"));
- }
-
- @Override
- public Result getEntrustWalletCoinOrder(String symbol, Integer status) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- OrderWalletCoinListVo orderWalletCoinListVo = new OrderWalletCoinListVo();
-
- List<OrderWalletCoinVo> arrayList = new ArrayList<>();
- List<OrderCoinsEntity> findCoinOrderListByMemberIdAndSysmbol = orderCoinsDao.findCoinOrderListByMemberIdAndSysmbol(memberId, symbol, status);
- if (CollUtil.isNotEmpty(findCoinOrderListByMemberIdAndSysmbol)) {
- for (OrderCoinsEntity orderCoinsEntity : findCoinOrderListByMemberIdAndSysmbol) {
- OrderWalletCoinVo entityToVo = OrderWalletCoinMapper.INSTANCE.entityToVo(orderCoinsEntity);
- entityToVo.setFeeAmount(entityToVo.getFeeAmount()== null
- ? BigDecimal.ZERO : entityToVo.getFeeAmount().setScale(4, BigDecimal.ROUND_DOWN));
- entityToVo.setMarkPrice(entityToVo.getMarkPrice()== null
- ? BigDecimal.ZERO : entityToVo.getMarkPrice().setScale(4, BigDecimal.ROUND_DOWN));
- entityToVo.setEntrustCnt(entityToVo.getEntrustCnt()== null
- ? BigDecimal.ZERO : entityToVo.getEntrustCnt().setScale(4, BigDecimal.ROUND_DOWN));
- entityToVo.setEntrustPrice(entityToVo.getEntrustPrice()== null
- ? BigDecimal.ZERO : entityToVo.getEntrustPrice().setScale(4, BigDecimal.ROUND_DOWN));
- entityToVo.setDealCnt(entityToVo.getDealCnt()== null
- ? BigDecimal.ZERO : entityToVo.getDealCnt().setScale(4, BigDecimal.ROUND_DOWN));
- entityToVo.setDealPrice(entityToVo.getDealPrice()== null
- ? BigDecimal.ZERO : entityToVo.getDealPrice().setScale(4, BigDecimal.ROUND_DOWN));
- entityToVo.setDealAmount(entityToVo.getDealAmount()== null
- ? BigDecimal.ZERO : entityToVo.getDealAmount().setScale(4, BigDecimal.ROUND_DOWN));
- arrayList.add(entityToVo);
- }
- }
- orderWalletCoinListVo.setOrderWalletCoinVo(arrayList);
- return Result.ok(arrayList);
- }
-
- @Override
- @Transactional
- public Result cancelEntrustWalletCoinOrder(String orderId) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- OrderCoinsEntity orderCoinsEntity = orderCoinsDao.selectById(orderId);
- if (ObjectUtil.isNotEmpty(orderCoinsEntity) && orderCoinsEntity.getMemberId() == memberId) {
- if (orderCoinsEntity.getOrderStatus() == OrderCoinsEntity.ORDERSTATUS_CANCEL) {
- return Result.fail(MessageSourceUtils.getString("order_service_0012"));
- }
- orderCoinsEntity.setOrderStatus(OrderCoinsEntity.ORDERSTATUS_CANCEL);
- orderCoinsDao.updateById(orderCoinsEntity);
-
- String symbol = orderCoinsEntity.getSymbol();
-
- OrderCoinsDealEntity detail = new OrderCoinsDealEntity();
- detail.setMemberId(memberId);
- detail.setOrderId(orderCoinsEntity.getId());
- detail.setOrderNo(generateSimpleSerialno(memberId.toString()));
- detail.setOrderType(orderCoinsEntity.getOrderType());
- detail.setTradeType(orderCoinsEntity.getTradeType());
- detail.setSymbol(symbol);
- detail.setOrderStatus(OrderCoinsDealEntity.ORDERSTATUS_CANCEL);
- detail.setSymbolCnt(orderCoinsEntity.getEntrustCnt());
- detail.setEntrustPrice(orderCoinsEntity.getEntrustPrice());
- detail.setDealPrice(orderCoinsEntity.getDealPrice());
- detail.setDealAmount(orderCoinsEntity.getDealAmount());
- detail.setFeeAmount(orderCoinsEntity.getFeeAmount());
- orderCoinDealDao.insert(detail);
-
- if (OrderCoinsEntity.ORDERTYPE_BUY.equals(orderCoinsEntity.getOrderType())) {
- //如果是限价买入,撤单将USDT账户冻结金额返回
- String walletCode = MemberWalletCoinEnum.WALLETCOINCODE.getValue();
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, walletCode);
-
- if (ObjectUtil.isNotEmpty(walletCoin)) {
- //手续费 = 开仓价*数量*手续费率
- //返还金额=开仓价*未成交数量+手续费
- BigDecimal returnBalance = orderCoinsEntity.getDealAmount();
-
- walletCoin.setAvailableBalance(walletCoin.getAvailableBalance().add(returnBalance));
- walletCoin.setFrozenBalance(walletCoin.getFrozenBalance().subtract(returnBalance));
- memberWalletCoinDao.updateById(walletCoin);
- // 流水记录
- MemberAccountFlowEntity record = new MemberAccountFlowEntity();
- record.setSource(MemberAccountFlowEntity.SOURCE_CANCEL);
- record.setRemark(MemberAccountFlowEntity.REMARK_CANCEL + symbol + MemberAccountFlowEntity.REMARK_RETURNBALANCE + returnBalance);
- record.setBalance(walletCoin.getAvailableBalance());
- record.setMemberId(memberId);
- record.setSymbol(symbol);
- record.setPrice(returnBalance);
- memberAccountFlowEntityDao.insert(record);
- return Result.ok(MessageSourceUtils.getString("order_service_0013"));
- }
- } else {
- //如果是限价卖出,撤单将对应的钱包冻结金额返回
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, symbol);
- if (ObjectUtil.isNotEmpty(walletCoin)) {
-
- BigDecimal returnBalance = orderCoinsEntity.getEntrustCnt();
- walletCoin.setAvailableBalance(walletCoin.getAvailableBalance().add(returnBalance));
- walletCoin.setFrozenBalance(walletCoin.getFrozenBalance().subtract(returnBalance));
- memberWalletCoinDao.updateById(walletCoin);
- // 流水记录
- MemberAccountFlowEntity record = new MemberAccountFlowEntity();
- record.setSource(MemberAccountFlowEntity.SOURCE_CANCEL);
- record.setRemark(MemberAccountFlowEntity.REMARK_CANCEL + symbol + MemberAccountFlowEntity.REMARK_RETURNBALANCE + returnBalance);
- record.setBalance(walletCoin.getAvailableBalance());
- record.setMemberId(memberId);
- record.setSymbol(symbol);
- record.setPrice(walletCoin.getFrozenBalance());
- memberAccountFlowEntityDao.insert(record);
- return Result.ok(MessageSourceUtils.getString("order_service_0013"));
- }
- }
- }
- return Result.fail(MessageSourceUtils.getString("order_service_0043"));
- }
-
- @Override
- public Result findAllWalletCoinOrder(FindAllWalletCoinOrderDto findAllWalletCoinOrderDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
-
- Page<OrderCoinsDealEntity> page = new Page<>(findAllWalletCoinOrderDto.getPageNum(), findAllWalletCoinOrderDto.getPageSize());
- OrderCoinsDealEntity orderCoinsDealEntity = new OrderCoinsDealEntity();
- orderCoinsDealEntity.setMemberId(memberId);
- orderCoinsDealEntity.setSymbol(findAllWalletCoinOrderDto.getSymbol());
- IPage<OrderCoinsDealEntity> list = orderCoinDealDao.findAllWalletCoinOrderInPage(page, orderCoinsDealEntity);
- Page<OrderWalletCoinDealVo> pageEntityToPageVo = OrderWalletCoinDealMapper.INSTANCE.pageEntityToPageVo(list);
- List<OrderWalletCoinDealVo> records = pageEntityToPageVo.getRecords();
- if(CollUtil.isNotEmpty(records)) {
- for(OrderWalletCoinDealVo orderWalletCoinDealVo : records) {
- orderWalletCoinDealVo.setFeeAmount(orderWalletCoinDealVo.getFeeAmount() == null
- ? BigDecimal.ZERO : orderWalletCoinDealVo.getFeeAmount().setScale(4, BigDecimal.ROUND_DOWN));
-
- orderWalletCoinDealVo.setDealAmount(orderWalletCoinDealVo.getDealAmount() == null
- ? BigDecimal.ZERO : orderWalletCoinDealVo.getDealAmount().setScale(4, BigDecimal.ROUND_DOWN));
-
- orderWalletCoinDealVo.setSymbolCnt(orderWalletCoinDealVo.getSymbolCnt() == null
- ? BigDecimal.ZERO : orderWalletCoinDealVo.getSymbolCnt().setScale(4, BigDecimal.ROUND_DOWN));
-
- orderWalletCoinDealVo.setEntrustPrice(orderWalletCoinDealVo.getEntrustPrice() == null
- ? BigDecimal.ZERO : orderWalletCoinDealVo.getEntrustPrice().setScale(4, BigDecimal.ROUND_DOWN));
-
- orderWalletCoinDealVo.setDealPrice(orderWalletCoinDealVo.getDealPrice() == null
- ? BigDecimal.ZERO : orderWalletCoinDealVo.getDealPrice().setScale(4, BigDecimal.ROUND_DOWN));
- }
- }
-
-
- return Result.ok(pageEntityToPageVo);
- }
-
- @Override
- public Result findWalletCoinOrder(Long orderId) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- OrderCoinsDealEntity selectWalletCoinOrder = orderCoinDealDao.selectWalletCoinOrder(orderId, memberId);
- OrderWalletCoinDealVo entityToVo = OrderWalletCoinDealMapper.INSTANCE.entityToVoOrder(selectWalletCoinOrder);
- if(ObjectUtil.isNotEmpty(entityToVo)) {
- entityToVo.setFeeAmount(entityToVo.getFeeAmount() == null
- ? BigDecimal.ZERO : entityToVo.getFeeAmount().setScale(4, BigDecimal.ROUND_DOWN));
-
- entityToVo.setDealAmount(entityToVo.getDealAmount() == null
- ? BigDecimal.ZERO : entityToVo.getDealAmount().setScale(4, BigDecimal.ROUND_DOWN));
-
- entityToVo.setSymbolCnt(entityToVo.getSymbolCnt() == null
- ? BigDecimal.ZERO : entityToVo.getSymbolCnt().setScale(4, BigDecimal.ROUND_DOWN));
-
- entityToVo.setEntrustPrice(entityToVo.getEntrustPrice() == null
- ? BigDecimal.ZERO : entityToVo.getEntrustPrice().setScale(4, BigDecimal.ROUND_DOWN));
-
- entityToVo.setDealPrice(entityToVo.getDealPrice() == null
- ? BigDecimal.ZERO : entityToVo.getDealPrice().setScale(4, BigDecimal.ROUND_DOWN));
- }
- return Result.ok(entityToVo);
- }
-
- @Override
- public Result findCollect(String symbol, Integer type) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- if (type == 1) {
- //添加自选
- MemberSelectSymbolsEntity symbols = new MemberSelectSymbolsEntity();
- symbols.setMemberId(memberId);
- symbols.setSymbol(symbol);
- memberSelectSymbolsDao.insert(symbols);
- return Result.ok(MessageSourceUtils.getString("order_service_0015"));
- } else {
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("symbol", symbol);
- columnMap.put("member_id", memberId);
- memberSelectSymbolsDao.deleteByMap(columnMap);
- ;
- return Result.ok(MessageSourceUtils.getString("order_service_0016"));
- }
- }
-
- @Override
- public Result checkIsCollect(String symbol) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberSelectSymbolsVo memberSelectSymbolsVo = new MemberSelectSymbolsVo();
- List<MemberSelectSymbolsEntity> selectSymbolByMemIdAndSymbol = memberSelectSymbolsDao.selectSymbolByMemIdAndSymbol(memberId, symbol);
-
- if (CollUtil.isNotEmpty(selectSymbolByMemIdAndSymbol)) {
- memberSelectSymbolsVo.setIsCollect(MemberSelectSymbolsVo.ISCOLLECT_YES);
- } else {
- memberSelectSymbolsVo.setIsCollect(MemberSelectSymbolsVo.ISCOLLECT_NO);
- }
- memberSelectSymbolsVo.setSymbol(symbol);
- return Result.ok(memberSelectSymbolsVo);
- }
-
- @Override
- public Result findCollectList() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- List<MemberSelectSymbolsEntity> selectByMap = memberSelectSymbolsDao.selectSymbolByMemId(memberId);
-
- FindCollectListVo findCollectListVo = new FindCollectListVo();
- List<MemberSelectSymbolsVo> arrayList = new ArrayList<>();
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (MemberSelectSymbolsEntity memberSelectSymbolsEntity : selectByMap) {
- MemberSelectSymbolsVo memberSelectSymbolsVo = new MemberSelectSymbolsVo();
- memberSelectSymbolsVo.setSymbol(memberSelectSymbolsEntity.getSymbol());
- arrayList.add(memberSelectSymbolsVo);
- }
- }
- findCollectListVo.setMemberSelectSymbolsVo(arrayList);
-
- return Result.ok(findCollectListVo);
- }
-
- @Override
- public Result searchSymbolResultList() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- FindCollectListVo findCollectListVo = new FindCollectListVo();
- List<MemberSelectSymbolsVo> list = new ArrayList<>();
-
- Map<String, Object> columnMap = new HashMap<>();
- List<PlatformSymbolsCoinEntity> selectByMap = platformSymbolsCoinDao.selectByMap(columnMap);
-
- List<MemberSelectSymbolsEntity> selectSymbolByMemIdAndSymbol = memberSelectSymbolsDao.selectSymbolByMemId(memberId);
- for (PlatformSymbolsCoinEntity platformSymbolsCoinEntity : selectByMap) {
- MemberSelectSymbolsVo memberSelectSymbolsVo = new MemberSelectSymbolsVo();
- memberSelectSymbolsVo.setSymbol(platformSymbolsCoinEntity.getName());
- if (CollUtil.isNotEmpty(selectSymbolByMemIdAndSymbol)) {
- for (MemberSelectSymbolsEntity memberSelectSymbolsEntity : selectSymbolByMemIdAndSymbol) {
- if (platformSymbolsCoinEntity.getName().equals(memberSelectSymbolsEntity.getSymbol())) {
- memberSelectSymbolsVo.setIsCollect(MemberSelectSymbolsVo.ISCOLLECT_YES);
- }
- }
- } else {
- memberSelectSymbolsVo.setIsCollect(MemberSelectSymbolsVo.ISCOLLECT_NO);
- }
- list.add(memberSelectSymbolsVo);
- }
- findCollectListVo.setMemberSelectSymbolsVo(list);
- return Result.ok(findCollectListVo);
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void dealEntrustCoinOrder() {
- List<OrderCoinsEntity> list = orderCoinsDao.selectAllEntrustingCoinOrderList();
- if (CollUtil.isNotEmpty(list)) {
- for (OrderCoinsEntity orderCoinsEntity : list) {
- BigDecimal nowPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(orderCoinsEntity.getSymbol() + "/USDT")));
- // 下单时市场价
- BigDecimal markPrice = orderCoinsEntity.getMarkPrice();
- // 委托价
- BigDecimal entrustPrice = orderCoinsEntity.getEntrustPrice();
-
- //如果当时委托价小于市价
- if (entrustPrice.compareTo(markPrice) < 0) {
- if (nowPrice.compareTo(entrustPrice) > 0) {
- continue;
- }
- } else {
- //委托价大于市价
- if (nowPrice.compareTo(entrustPrice) < 0) {
- continue;
- }
- }
-
- BigDecimal fee = entrustPrice.multiply(orderCoinsEntity.getEntrustCnt()).multiply(new BigDecimal("0.002")).setScale(8, BigDecimal.ROUND_HALF_UP);
-
- BigDecimal dealAmount = entrustPrice.multiply(orderCoinsEntity.getEntrustCnt());
-
- OrderCoinsDealEntity orderCoinsDealEntity = OrderCoinsDealMapper.INSTANCE.orderToOrderDeal(orderCoinsEntity);
- orderCoinsDealEntity.setDealAmount(dealAmount);
- orderCoinsDealEntity.setDealPrice(entrustPrice);
- orderCoinsDealEntity.setFeeAmount(fee);
- orderCoinsDealEntity.setOrderStatus(OrderCoinsDealEntity.ORDERSTATUS_DONE);
- orderCoinsDealEntity.setId(null);
- orderCoinDealDao.insert(orderCoinsDealEntity);
-
- orderCoinsDao.deleteById(orderCoinsEntity.getId());
-
- MemberWalletCoinEntity walletCoinEntity = memberWalletCoinDao.selectWalletCoinBymIdAndCode(orderCoinsEntity.getMemberId(), orderCoinsEntity.getSymbol());
- MemberWalletCoinEntity usdt = memberWalletCoinDao.selectWalletCoinBymIdAndCode(orderCoinsEntity.getMemberId(), "USDT");
-
- BigDecimal frozen = BigDecimal.ZERO;
- BigDecimal total = BigDecimal.ZERO;
- // 买入
- if (OrderCoinsEntity.ORDERTYPE_BUY.equals(orderCoinsEntity.getOrderType())) {
- BigDecimal newCoins = walletCoinEntity.getAvailableBalance().add(orderCoinsEntity.getEntrustCnt());
- BigDecimal newCoinTotal = walletCoinEntity.getTotalBalance().add(orderCoinsEntity.getEntrustCnt());
- walletCoinEntity.setAvailableBalance(newCoins);
- walletCoinEntity.setTotalBalance(newCoinTotal);
- memberWalletCoinDao.updateById(walletCoinEntity);
-
- frozen = usdt.getFrozenBalance().subtract(dealAmount.add(fee));
- total = usdt.getTotalBalance().subtract(dealAmount.add(fee));
- usdt.setFrozenBalance(frozen);
- usdt.setTotalBalance(total);
- memberWalletCoinDao.updateById(usdt);
- } else {
- walletCoinEntity.setFrozenBalance(walletCoinEntity.getFrozenBalance().subtract(orderCoinsEntity.getEntrustCnt()));
- walletCoinEntity.setTotalBalance(walletCoinEntity.getTotalBalance().subtract(orderCoinsEntity.getEntrustCnt()));
- memberWalletCoinDao.updateById(walletCoinEntity);
-
- usdt.setAvailableBalance(usdt.getAvailableBalance().add(dealAmount.add(fee)));
- usdt.setTotalBalance(usdt.getTotalBalance().add(dealAmount.add(fee)));
- memberWalletCoinDao.updateById(usdt);
- }
- }
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/controller/ContractEntrustOrderController.java b/src/main/java/com/xcong/excoin/modules/contract/controller/ContractEntrustOrderController.java
deleted file mode 100644
index 7d1430b..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/controller/ContractEntrustOrderController.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.xcong.excoin.modules.contract.controller;
-
-import cn.hutool.core.util.StrUtil;
-import com.xcong.excoin.common.enumerates.SymbolEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.contract.parameter.dto.SubmitEntrustDto;
-import com.xcong.excoin.modules.contract.parameter.vo.ContractEntrustVo;
-import com.xcong.excoin.modules.contract.service.ContractEntrustOrderService;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import com.xcong.excoin.utils.TypeJudgeUtils;
-import com.xcong.excoin.utils.api.response.Symbol;
-import io.swagger.annotations.*;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-
-/**
- * 合约委托订单controller
- *
- * @author wzy
- * @date 2020-05-27
- **/
-@Slf4j
-@Api(value = "ContractEntrustOrderController", tags = "合约委托订单接口类")
-@RestController
-@RequestMapping(value = "/api/contractEntrust")
-public class ContractEntrustOrderController {
-
- @Resource
- private ContractEntrustOrderService contractEntrustOrderService;
-
- @ApiOperation(value = "合约提交委托订单", notes = "提交委托订单")
- @PostMapping(value = "/submitEntrustOrder")
- public Result submitEntrustOrder(@RequestBody @Validated SubmitEntrustDto submitEntrustDto) {
- if (StrUtil.isBlank(SymbolEnum.getNameByValue(submitEntrustDto.getSymbol()))) {
- return Result.fail(MessageSourceUtils.getString("illegal_symbol"));
- }
-
- if (!TypeJudgeUtils.entrustType(submitEntrustDto.getEntrustType())) {
- return Result.fail(MessageSourceUtils.getString("illegal_type"));
- }
-
- return contractEntrustOrderService.addContractEntrustOrder(submitEntrustDto);
- }
-
- @ApiOperation(value = "获取当前委托单列表", notes = "获取当前委托单列表")
- @ApiResponses({
- @ApiResponse(code = 0, message = "success", response = ContractEntrustVo.class)
- })
- @GetMapping(value = "/findCurrentEntrustOrderList")
- public Result findCurrentEntrustOrderList(@ApiParam(name = "symbol", value = "币种", example = "BTC/USDT") @RequestParam(value = "symbol", required = false) String symbol) {
- return contractEntrustOrderService.findEntrustOrderList(symbol);
- }
-
-
- @ApiOperation(value = "撤销委托单", notes = "撤销委托单")
- @GetMapping(value = "/cancelEntrustOrder")
- public Result cancelEntrustOrder(@ApiParam(name = "id", value = "委托单ID", required = true, example = "1") @RequestParam("id") Long id) {
- return contractEntrustOrderService.cancelEntrustOrder(id);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/controller/ContractHoldOrderController.java b/src/main/java/com/xcong/excoin/modules/contract/controller/ContractHoldOrderController.java
deleted file mode 100644
index 71fafda..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/controller/ContractHoldOrderController.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.contract.controller;
-
-import io.swagger.annotations.Api;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * @author wzy
- * @date 2020-05-27
- **/
-@Slf4j
-@Api(value = "ContractHoldOrderController", tags = "合约持仓订单接口类")
-@RestController
-@RequestMapping(value = "/api/contractHold")
-public class ContractHoldOrderController {
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/controller/ContractOrderController.java b/src/main/java/com/xcong/excoin/modules/contract/controller/ContractOrderController.java
deleted file mode 100644
index 0be9cc1..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/controller/ContractOrderController.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.xcong.excoin.modules.contract.controller;
-
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.contract.parameter.dto.*;
-import com.xcong.excoin.modules.contract.parameter.vo.ContractMoneyInfoVo;
-import com.xcong.excoin.modules.contract.parameter.vo.HoldOrderListVo;
-import com.xcong.excoin.modules.contract.parameter.vo.OrderListVo;
-import com.xcong.excoin.modules.contract.service.ContractHoldOrderService;
-import com.xcong.excoin.modules.contract.service.ContractOrderService;
-import com.xcong.excoin.rabbit.producer.OrderProducer;
-import io.swagger.annotations.*;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-
-/**
- * @author wzy
- * @date 2020-05-27
- **/
-@Slf4j
-@Api(value = "ContractOrderController", tags = "合约订单接口类")
-@RestController
-@RequestMapping(value = "/api/contractOrder")
-public class ContractOrderController {
-
- @Resource
- private ContractHoldOrderService contractHoldOrderService;
-
- @Resource
- private ContractOrderService contractOrderService;
-
- @ApiOperation(value = "市价提交合约订单")
- @PostMapping(value = "/submitOrder")
- public Result submitOrder(@RequestBody SubmitOrderDto submitOrderDto) {
- return contractHoldOrderService.submitOrder(submitOrderDto);
- }
-
- @ApiOperation(value = "查询当前持仓订单列表 -- 轮询")
- @ApiResponses({
- @ApiResponse(code = 0, message = "success", response = HoldOrderListVo.class)
- })
- @GetMapping(value = "/findHoldOrderList")
- public Result findHoldOrderList(@ApiParam(name = "symbol", value = "币种", example = "BTC/USDT") @RequestParam(value = "symbol", required = false) String symbol) {
- return contractHoldOrderService.findHoldOrderList(symbol);
- }
-
- @ApiOperation(value = "根据Id查询持仓订单详情")
- @GetMapping(value = "/findHoldOrderDetail")
- public Result findHoldOrderDetail(@ApiParam(name = "id", value = "持仓ID", required = true, example = "1") @RequestParam(value = "id") Long id) {
- return contractHoldOrderService.findHoldOrderDetailById(id);
- }
-
- @ApiOperation(value = "根据Id平仓")
- @GetMapping(value = "/closingOrder")
- public Result closingOrder(@ApiParam(name = "id", value = "持仓ID", required = true, example = "1") @RequestParam(value = "id") Long id) {
- return contractHoldOrderService.cancelHoldOrder(id);
- }
-
- @ApiOperation(value = "一键平仓")
- @PostMapping(value = "/oneKeyClosing")
- public Result oneKeyClosing(@RequestBody SymbolDto symbolDto) {
- return contractHoldOrderService.cancelHoldOrderBatch(symbolDto);
- }
-
- @ApiOperation(value = "设置止盈止损")
- @PostMapping(value = "/setTargetProfitOrLoss")
- public Result setTargetProfitOrLoss(@RequestBody @Validated ProfitOrLessDto profitOrLessDto) {
- return contractHoldOrderService.setTargetProfitOrLess(profitOrLessDto);
- }
-
- @ApiOperation(value = "调整保证金")
- @PostMapping(value = "/changeBond")
- public Result changeBond(@RequestBody @Validated ChangeBondDto changeBondDto) {
- return contractHoldOrderService.changeBond(changeBondDto);
- }
-
- @ApiOperation(value = "分页查询历史订单列表")
- @ApiResponses({
- @ApiResponse(code = 0, message = "success", response = OrderListVo.class)
- })
- @PostMapping(value = "/findHistoryOrderList")
- public Result findHistoryOrderList(@RequestBody @Validated OrderListDto orderListDto) {
- return contractHoldOrderService.findOrderList(orderListDto);
- }
-
- @ApiOperation(value = "获取合约页面资产信息")
- @ApiResponses({
- @ApiResponse(code = 0, message = "success", response = ContractMoneyInfoVo.class)
- })
- @GetMapping(value = "/findContractMoneyInfo")
- public Result findContractMoneyInfo(@ApiParam(name = "symbol", value = "币种", required = true, example = "BTC/USDT") @RequestParam(value = "symbol") String symbol) {
- return contractHoldOrderService.findContractMoneyInfo(symbol);
- }
-
- @ApiOperation(value = "调整杠杆")
- @PostMapping(value = "/changeLeverRate")
- public Result changeLeverRate(@RequestBody @Validated ChangeLeverRateDto changeLeverRateDto) {
- return contractHoldOrderService.changeLeverRate(changeLeverRateDto);
- }
-
- @ApiOperation(value = "查询历史委托订单详情")
- @GetMapping(value = "/findOrderDetailById")
- public Result findOrderDetailById(@ApiParam(name = "id", value = "订单id", required = true, example = "1") @RequestParam(value = "id") Long id) {
- return contractHoldOrderService.findOrderDetailById(id);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/dao/ContractEntrustOrderDao.java b/src/main/java/com/xcong/excoin/modules/contract/dao/ContractEntrustOrderDao.java
deleted file mode 100644
index 3f07e27..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/dao/ContractEntrustOrderDao.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.contract.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface ContractEntrustOrderDao extends BaseMapper<ContractEntrustOrderEntity> {
-
- public ContractEntrustOrderEntity selectEntrustOrderByIdAndMemberId(@Param("id") Long id, @Param("memberId") Long memberId);
-
- public List<ContractEntrustOrderEntity> selectEntrustOrderListByMemberId(@Param("memberId") Long memberId);
-
- public List<ContractEntrustOrderEntity> selectEntrustOrderListByMemberIdAndSymbol(@Param("memberId") Long memberId, @Param("symbol") String symbol);
-
- public List<ContractEntrustOrderEntity> selectEntrustOrderListByIds(@Param("list") List<Long> list);
-
- public List<ContractEntrustOrderEntity> selectAllEntrustOrder();
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/dao/ContractHoldOrderDao.java b/src/main/java/com/xcong/excoin/modules/contract/dao/ContractHoldOrderDao.java
deleted file mode 100644
index dd1f6ac..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/dao/ContractHoldOrderDao.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.xcong.excoin.modules.contract.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface ContractHoldOrderDao extends BaseMapper<ContractHoldOrderEntity> {
- /**
- * 根据ids更新所有订单的平仓状态
- *
- * @param list
- * @return
- */
- int updateContractHoldOrderCanNotClosingByIds(@Param("list") List<OrderModel> list, @Param("batchNo") String batchNo);
-
- /**
- * 根据批次号查询次仓订单
- *
- * @param batchNo
- * @return
- */
- List<ContractHoldOrderEntity> selectContractHoldOrderByBatchNo(@Param("batchNo") String batchNo);
-
- /**
- * 更新该订单为可平仓状态
- *
- * @param id
- */
- public void updateOrderIsCanClosingAndBatchNoById(@Param("id") Long id);
-
- public List<ContractHoldOrderEntity> selectHoldOrderListByMemberId(@Param("memberId") Long memberId);
-
- public List<ContractHoldOrderEntity> selectHoldOrderListByMemberIdAndSymbol(@Param("memberId") Long memberId, @Param("symbol") String symbol);
-
- public ContractHoldOrderEntity selectHoldOrderByMemberIdAndId(@Param("memberId") Long memberId, @Param("id") Long id);
-
- public int updateHoldOrderIsCanClosingById(@Param("isCanClosing") int isCanClosing, @Param("id") Long id);
-
- public List<ContractHoldOrderEntity> selectAllHoldOrder();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/dao/ContractOrderDao.java b/src/main/java/com/xcong/excoin/modules/contract/dao/ContractOrderDao.java
deleted file mode 100644
index aaea6dc..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/dao/ContractOrderDao.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.xcong.excoin.modules.contract.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.dto.OrderListDto;
-import com.xcong.excoin.modules.contract.parameter.vo.OrderListVo;
-import org.apache.ibatis.annotations.Param;
-
-/**
- * @author helius
- */
-public interface ContractOrderDao extends BaseMapper<ContractOrderEntity> {
-
- public IPage<ContractOrderEntity> selectContractOrderInPage(Page<ContractOrderEntity> page, @Param("record") ContractOrderEntity contractOrderEntity);
-
- public ContractOrderEntity selectOrderDetailByIdAndMemberId(@Param("id") Long id, @Param("memberId") Long memberId);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/entity/ContractEntrustOrderEntity.java b/src/main/java/com/xcong/excoin/modules/contract/entity/ContractEntrustOrderEntity.java
deleted file mode 100644
index ee1067b..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/entity/ContractEntrustOrderEntity.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.xcong.excoin.modules.contract.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * @author wzy
- * @date 2020-05-27
- **/
-@Data
-@TableName("contract_entrust_order")
-public class ContractEntrustOrderEntity extends BaseEntity {
-
- public static final int ENTRUST_TYPE_OPEN_MORE = 1;
-
- public static final int ENTRUST_TYPE_OPEN_LESS = 2;
-
- public static final int ENTRUST_TYPE_CLOSE_MORE = 3;
-
- public static final int ENTRUST_TYPE_CLOSE_LESS = 4;
-
- /**
- * 逐仓
- */
- public static final int POSITION_TYPE_ADD = 1;
-
- /**
- * 全仓
- */
- public static final int POSITION_TYPE_ALL = 2;
-
-
- /**
- * 会员ID
- */
- private Long memberId;
-
- /**
- * 订单编号
- */
- private String orderNo;
-
- /**
- * 仓位类型 1逐仓2全仓
- */
- private int positionType;
-
- /**
- * 委托类型 1开多,2开空,3平多,4平空
- */
- private int entrustType;
-
- /**
- * 委托价格
- */
- private BigDecimal entrustPrice;
-
- /**
- * 委托金额
- */
- private BigDecimal entrustAmount;
-
- /**
- * 币种
- */
- private String symbol;
-
- /**
- * 数量
- */
- private int symbolCnt;
-
- /**
- * 币种规格
- */
- private BigDecimal symbolSku;
-
- /**
- * 杠杆倍率
- */
- private int leverRatio;
-
- /**
- * 保证金
- */
- private BigDecimal bondAmount;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/entity/ContractHoldOrderEntity.java b/src/main/java/com/xcong/excoin/modules/contract/entity/ContractHoldOrderEntity.java
deleted file mode 100644
index 7da4069..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/entity/ContractHoldOrderEntity.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.xcong.excoin.modules.contract.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * 合约持仓订单表
- *
- * @author wzy
- * @date 2020-05-27
- **/
-@Data
-@TableName("contract_hold_order")
-public class ContractHoldOrderEntity extends BaseEntity {
-
- /**
- * 是否可平仓 1-是
- */
- public static final int ORDER_CAN_CLOSING_Y = 1;
- /**
- * 是否可平仓 0-否
- */
- public static final int ORDER_CAN_CLOSING_N = 0;
-
- /**
- * 开多
- */
- public static final int OPENING_TYPE_MORE = 1;
-
- /**
- * 开空
- */
- public static final int OPENING_TYPE_LESS = 2;
-
- /**
- * 交易类型 市价
- */
- public static final int TRADE_TYPE_MARK = 1;
-
- /**
- * 交易类型 限价
- */
- public static final int TRADE_TYPE_LIMIT = 2;
-
- /**
- * 会员Id
- */
- private Long memberId;
-
- /**
- * 订单编号
- */
- private String orderNo;
-
- /**
- * 仓位类型 1-逐仓 2-全仓
- */
- private int positionType;
-
- /**
- * 交易类型 1-市价 2-限价
- */
- private int tradeType;
-
- /**
- * 币种
- */
- private String symbol;
-
- /**
- * 手数
- */
- private int symbolCnt;
-
- /**
- * 可平张数(仅全仓模式)
- */
- private int symbolCntSale;
-
- /**
- * 币种规格
- */
- private BigDecimal symbolSku;
-
- /**
- * 开仓价
- */
- private BigDecimal openingPrice;
-
- /**
- * 开仓类型 1-开多 2-开空
- */
- private int openingType;
-
- /**
- * 开仓手续费
- */
- private BigDecimal openingFeeAmount;
-
- /**
- * 保证金
- */
- private BigDecimal bondAmount;
-
- /**
- * 杠杆倍率
- */
- private int leverRatio;
-
- /**
- * 市场价
- */
- private BigDecimal markPrice;
-
- /**
- * 止损价
- */
- private BigDecimal stopLossPrice;
-
- /**
- * 止盈价
- */
- private BigDecimal stopProfitPrice;
-
- /**
- * 预付款金额
- */
- private BigDecimal prePaymentAmount;
-
- /**
- * 预估强平价
- */
- private BigDecimal forceClosingPrice;
-
- private int operateNo;
-
- /**
- * 是否可平仓 0-否 1-是
- */
- private int isCanClosing;
-
- /**
- * 批次号 队列平仓时使用,避免重复
- */
- public String batchNo;
-
- /**
- * 持仓费
- */
- private BigDecimal holdAmount;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/entity/ContractOrderEntity.java b/src/main/java/com/xcong/excoin/modules/contract/entity/ContractOrderEntity.java
deleted file mode 100644
index 9a82765..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/entity/ContractOrderEntity.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package com.xcong.excoin.modules.contract.entity;
-
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.FieldStrategy;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 合约订单历史表
- *
- * @author wzy
- * @date 2020-05-27
- **/
-@Data
-@TableName("contract_order")
-public class ContractOrderEntity extends BaseEntity {
-
- /**
- * 交易类型 市价
- */
- public static final int TRADE_TYPE_MARK_PRICE = 1;
-
- /**
- * 交易类型 限价
- */
- public static final int TRADE_TYPE_LIMIT_PRICE = 2;
-
- /**
- * 订单状态 撤单
- */
- public static final int ORDER_STATUS_CANCEL = 2;
-
- /**
- * 订单状态 成交
- */
- public static final int ORDER_STATUS_SUCCESS = 1;
-
- /**
- * 订单类型 开多
- */
- public static final int ORDER_TYPE_OPEN_MORE = 1;
-
- /**
- * 订单类型 开空
- */
- public static final int ORDER_TYPE_OPEN_LESS = 2;
-
- /**
- * 订单类型 平多
- */
- public static final int ORDER_TYPE_CLOSE_MORE = 3;
-
- /**
- * 订单类型 平空
- */
- public static final int ORDER_TYPE_CLOSE_LESS = 4;
-
-
- /**
- * 会员Id
- */
- private Long memberId;
-
- /**
- * 订单编号
- */
- private String orderNo;
-
- /**
- * 仓位类型 1-逐仓 2-全仓
- */
- private int positionType;
-
- /**
- * 交易类型 1-市价 2-限价
- */
- private int tradeType;
-
- /**
- * 订单类型 - 1开多,2开空,3平多,4平空
- */
- private int orderType;
-
- /**
- * 订单状态 - 1成交 2撤单
- */
- private int orderStatus = 1;
-
- /**
- * 委托开仓价
- */
- private BigDecimal entrustOpeningPrice;
-
- /**
- * 委托时间
- */
- private Date entrustTime;
-
- /**
- * 币种
- */
- private String symbol;
-
- /**
- * 手数
- */
- private int symbolCnt;
-
- /**
- * 币种规格
- */
- private BigDecimal symbolSku;
-
- /**
- * 平仓价
- */
- private BigDecimal closingPrice;
-
- /**
- * 平仓手续费
- */
- private BigDecimal closingFeeAmount;
-
- /**
- * 平仓时间
- */
- private Date closingTime;
-
- /**
- * 平仓类型 2平多3平空4爆仓平多5爆仓平空6止盈平多7止盈平空8止损平多9止损平空
- */
- private int closingType;
-
- /**
- * 杠杆倍率
- */
- private int leverRatio;
-
- /**
- * 止损价
- */
- private BigDecimal stopLossPrice;
-
- /**
- * 止盈价
- */
- private BigDecimal stopProfitPrice;
-
- /**
- * 盈亏金额
- */
- private BigDecimal rewardAmount;
-
- /**
- * 盈亏比例
- */
- private BigDecimal rewardRatio;
-
- /**
- * 开仓价
- */
- private BigDecimal openingPrice;
-
- /**
- * 开仓手续费
- */
- private BigDecimal openingFeeAmount;
-
- private Date openingTime;
-
- /**
- * 预付款金额
- */
- private BigDecimal prePaymentAmount;
-
- /**
- * 保证金
- */
- private BigDecimal bondAmount;
-
- /**
- * 市场价
- */
- private BigDecimal markPrice;
-
- /**
- * 预估强平价
- */
- private BigDecimal forceClosingPrice;
-
- /**
- * 持仓费
- */
- private BigDecimal holdAmount;
-
- private int operateNo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractEntrustOrderEntityMapper.java b/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractEntrustOrderEntityMapper.java
deleted file mode 100644
index a80d1ef..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractEntrustOrderEntityMapper.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin.modules.contract.mapper;
-
-import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.dto.SubmitEntrustDto;
-import com.xcong.excoin.modules.contract.parameter.vo.ContractEntrustVo;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-28
- **/
-@Mapper
-public abstract class ContractEntrustOrderEntityMapper {
- public static final ContractEntrustOrderEntityMapper INSTANCE = Mappers.getMapper(ContractEntrustOrderEntityMapper.class);
-
- public abstract ContractEntrustOrderEntity submitEntrustDtoToEntity(SubmitEntrustDto dto);
-
- @Mapping(source = "entrustPrice", target = "entrustOpeningPrice")
- @Mapping(source = "createTime", target = "entrustTime")
- @Mapping(source = "entrustAmount", target = "prePaymentAmount")
- @Mapping(source = "entrustType", target = "orderType")
- public abstract ContractOrderEntity entrustOrderToOrder(ContractEntrustOrderEntity orderEntity);
-
- @Mapping(source = "createTime", target = "entrustTime")
- @Mapping(source = "entrustType", target = "type")
- public abstract ContractEntrustVo entityToContractEntrustVo(ContractEntrustOrderEntity orderEntity);
-
- public abstract List<ContractEntrustVo> entityListToVoList(List<ContractEntrustOrderEntity> list);
-
- @Mapping(source = "entrustAmount", target = "prePaymentAmount")
- public abstract ContractHoldOrderEntity entrustOrderToHoldOrder(ContractEntrustOrderEntity entrustOrderEntity);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractHoldOrderEntityMapper.java b/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractHoldOrderEntityMapper.java
deleted file mode 100644
index b2ad5e4..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractHoldOrderEntityMapper.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.xcong.excoin.modules.contract.mapper;
-
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.vo.HoldOrderDetailVo;
-import com.xcong.excoin.modules.contract.parameter.vo.HoldOrderListVo;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.factory.Mappers;
-
-/**
- * @author wzy
- * @date 2020-05-31
- **/
-@Mapper
-public abstract class ContractHoldOrderEntityMapper {
- public static final ContractHoldOrderEntityMapper INSTANCE = Mappers.getMapper(ContractHoldOrderEntityMapper.class);
-
- @Mapping(target = "orderType", source = "openingType")
- @Mapping(target = "openingTime", source = "createTime")
- public abstract ContractOrderEntity holdOrderToOrder(ContractHoldOrderEntity holdOrderEntity);
-
- public abstract HoldOrderListVo holdOrderToDto(ContractHoldOrderEntity holdOrderEntity);
-
- @Mapping(target = "openingTime", source = "createTime")
- public abstract HoldOrderDetailVo holdOrderToOrderDetailVo(ContractHoldOrderEntity holdOrderEntity);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractOrderEntityMapper.java b/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractOrderEntityMapper.java
deleted file mode 100644
index b2e3ee2..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/mapper/ContractOrderEntityMapper.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.contract.mapper;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.vo.OrderDetailVo;
-import com.xcong.excoin.modules.contract.parameter.vo.OrderListVo;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-06-05
- **/
-@Mapper
-public abstract class ContractOrderEntityMapper {
- public static final ContractOrderEntityMapper INSTANCE = Mappers.getMapper(ContractOrderEntityMapper.class);
-
- public abstract OrderListVo orderEntityToOrderListVo(ContractOrderEntity orderEntity);
-
- public abstract List<OrderListVo> orderEntitiesToOrderListVo(List<ContractOrderEntity> orderEntities);
-
- public abstract Page<OrderListVo> pageEntityToPageVo(IPage<ContractOrderEntity> orderEntityIPage);
-
- public abstract OrderDetailVo entityToDetailVo(ContractOrderEntity orderEntity);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ChangeBondDto.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ChangeBondDto.java
deleted file mode 100644
index cbac1d1..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ChangeBondDto.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-06-02
- **/
-@Data
-@ApiModel(value = "ChangeBondDto", description = "调整保证金接口接受参数类")
-public class ChangeBondDto {
-
- public static final int TYPE_ADD = 1;
-
- public static final int TYPE_REDUCE = 2;
-
- @NotNull
- @ApiModelProperty(value = "订单ID", example = "1")
- private Long id;
-
- @NotNull
- @ApiModelProperty(value = "类型 1-增加2-减少", example = "1")
- private Integer type;
-
- @NotNull
- @Min(0)
- @ApiModelProperty(value = "金额", example = "90.00")
- private BigDecimal amount;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ChangeLeverRateDto.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ChangeLeverRateDto.java
deleted file mode 100644
index 4ba4265..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ChangeLeverRateDto.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-
-/**
- * @Author wzy
- * @Date 2020/6/5
- **/
-@Data
-@ApiModel(value = "ChangeLeverRateDto", description = "调整杠杆接口接收参数类")
-public class ChangeLeverRateDto {
-
- @NotNull
- @ApiModelProperty(value = "杠杆", example = "100")
- private int leverRate;
-
- @NotNull
- @ApiModelProperty(value = "币种", example = "BTC/USDT")
- private String symbol;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/OrderListDto.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/OrderListDto.java
deleted file mode 100644
index d194891..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/OrderListDto.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-
-/**
- * @Author wzy
- * @Date 2020/6/5
- **/
-@Data
-@ApiModel(value = "OrderListDto", description = "历史委托订单列表接口参数接受类")
-public class OrderListDto {
-
- @NotNull
- @Min(1)
- @ApiModelProperty(value = "第几页", example = "1")
- private int pageNum;
-
- @NotNull
- @ApiModelProperty(value = "每页数量", example = "10")
- private int pageSize;
-
- @NotNull
- @ApiModelProperty(value = "币种", example = "BTC/USDT")
- private String symbol;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ProfitOrLessDto.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ProfitOrLessDto.java
deleted file mode 100644
index ea0e60f..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/ProfitOrLessDto.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.DecimalMin;
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-06-02
- **/
-@Data
-@ApiModel(value = "ProfitOrLessDto", description = "设置止盈止损接口参数类")
-public class ProfitOrLessDto {
-
- @NotNull
- @ApiModelProperty(value = "订单ID", example = "1")
- private Long id;
-
- @ApiModelProperty(value = "止盈价", example = "9000.00")
- private BigDecimal stopProfitPrice;
-
- @ApiModelProperty(value = "止损价", example = "9000.00")
- private BigDecimal stopLessPrice;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SubmitEntrustDto.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SubmitEntrustDto.java
deleted file mode 100644
index bf588cb..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SubmitEntrustDto.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-05-27
- **/
-@Data
-@ApiModel(value = "SubmitEntrustDto", description = "提交委托订单接口接受类")
-public class SubmitEntrustDto {
-
- @NotNull()
- @Min(1)
- @ApiModelProperty(value = "委托价", example = "9000.00")
- private BigDecimal entrustPrice;
-
- @NotNull
- @ApiModelProperty(value = "委托类型 1开多 2开空 3平多 4平空", example = "1")
- private int entrustType;
-
- @NotBlank
- @ApiModelProperty(value = "币种", example = "BTC/USDT")
- private String symbol;
-
- @NotNull
- @Min(1)
- @ApiModelProperty(value = "币种数量", example = "1")
- private int symbolCnt;
-
- @NotNull
- @ApiModelProperty(value = "杠杆倍率", example = "100")
- private int leverRatio;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SubmitOrderDto.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SubmitOrderDto.java
deleted file mode 100644
index 2a6c692..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SubmitOrderDto.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-
-/**
- * @author wzy
- * @date 2020-05-31
- **/
-@Data
-@ApiModel(value = "SubmitOrderDto", description = "提交订单接口接受类")
-public class SubmitOrderDto {
-
- @NotNull
- @ApiModelProperty(value = "订单类型 1开多 2开空", example = "1")
- private int orderType;
-
- @NotBlank
- @ApiModelProperty(value = "币种", example = "BTC/USDT")
- private String symbol;
-
- @NotNull
- @Min(1)
- @ApiModelProperty(value = "币种数量", example = "1")
- private int symbolCnt;
-
- @NotNull
- @ApiModelProperty(value = "杠杆倍率", example = "100")
- private int leverRatio;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SymbolDto.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SymbolDto.java
deleted file mode 100644
index 4319d46..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/dto/SymbolDto.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * @author wzy
- * @date 2020-06-03
- **/
-@Data
-@ApiModel(value = "SymbolDto", description = "币种dto")
-public class SymbolDto {
-
- @ApiModelProperty(value = "币种", example = "BTC/USDT")
- private String symbol;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/ContractEntrustVo.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/ContractEntrustVo.java
deleted file mode 100644
index 1203690..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/ContractEntrustVo.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.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;
-
-/**
- * @author wzy
- * @date 2020-05-29
- **/
-@Data
-@ApiModel(value = "ContractEntrustVo", description = "合约委托")
-public class ContractEntrustVo {
-
- @ApiModelProperty(value = "委托单ID")
- private Long id;
-
- @ApiModelProperty(value = "委托价")
- private BigDecimal entrustPrice;
-
- @ApiModelProperty(value = "委托数量")
- private int symbolCnt;
-
- @ApiModelProperty(value = "保证金")
- private BigDecimal bondAmount;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone="GMT+8")
- @ApiModelProperty(value = "委托时间")
- private Date entrustTime;
-
- @ApiModelProperty(value = "委托类型 1-开多 2-开空")
- private int type;
-
- public String getBondAmount() {
- return bondAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/ContractMoneyInfoVo.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/ContractMoneyInfoVo.java
deleted file mode 100644
index 8ae1d67..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/ContractMoneyInfoVo.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @Author wzy
- * @Date 2020/6/2
- **/
-@Data
-@ApiModel(value = "ContractMoneyInfoVo", description = "合约资产信息接口返回参数类")
-public class ContractMoneyInfoVo {
-
- @ApiModelProperty(value = "占用保证金")
- private BigDecimal beUsedBondAmount;
-
- @ApiModelProperty(value = "冻结保证金")
- private BigDecimal frozenBondAmount;
-
- @ApiModelProperty(value = "手续费率")
- private BigDecimal feeRatio;
-
- @ApiModelProperty(value = "权益")
- private BigDecimal equity;
-
- @ApiModelProperty(value = "合约杠杆")
- private Integer leverRate;
-
- @ApiModelProperty(value = "倍率")
- private BigDecimal leverAgeRatio;
-
- @ApiModelProperty(value = "可用余额")
- private BigDecimal availableBalance;
-
- @ApiModelProperty(value = "最新价")
- private BigDecimal newPrice;
-
- @ApiModelProperty(value = "规格")
- private BigDecimal symbolSku;
-
- public BigDecimal getBeUsedBondAmount() {
- return beUsedBondAmount.setScale(4, BigDecimal.ROUND_DOWN);
- }
-
- public BigDecimal getFrozenBondAmount() {
- return frozenBondAmount.setScale(4, BigDecimal.ROUND_DOWN);
- }
-
- public BigDecimal getEquity() {
- return equity.setScale(4, BigDecimal.ROUND_DOWN);
- }
-
- public BigDecimal getAvailableBalance() {
- return availableBalance.setScale(4, BigDecimal.ROUND_DOWN);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/HoldOrderDetailVo.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/HoldOrderDetailVo.java
deleted file mode 100644
index 66f370b..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/HoldOrderDetailVo.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.vo;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * @author wzy
- * @date 2020-06-01
- **/
-@Data
-@ApiModel(value = "HoldOrderDetailVo", description = "获取持仓订单详情接口返回类")
-public class HoldOrderDetailVo {
-
- @ApiModelProperty("订单编号")
- private String orderNo;
-
- @ApiModelProperty("交易类型 1-市价2-限价")
- private int tradeType;
-
- @ApiModelProperty("币种")
- private String symbol;
-
- @ApiModelProperty("张数")
- private int symbolCnt;
-
- @ApiModelProperty("规格")
- private BigDecimal symbolSku;
-
- @ApiModelProperty("开仓价")
- private BigDecimal openingPrice;
-
- @ApiModelProperty("开仓类型 1-开多 2-开空")
- private int openingType;
-
- @ApiModelProperty("开仓手续费")
- private BigDecimal openingFeeAmount;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- @ApiModelProperty("开仓时间")
- private Date openingTime;
-
- @ApiModelProperty("保证金")
- private BigDecimal bondAmount;
-
- @ApiModelProperty("持仓费")
- private BigDecimal holdAmount;
-
- @ApiModelProperty("预估强平价")
- private BigDecimal forceClosingPrice;
-
- @ApiModelProperty("止损价")
- private BigDecimal stopLossPrice;
-
- @ApiModelProperty("止盈价")
- private BigDecimal stopProfitPrice;
-
- @ApiModelProperty("倍率杠杆")
- private int leverRatio;
-
- public String getOpeningPrice() {
- return openingPrice == null ? "" : openingPrice.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getOpeningFeeAmount() {
- return openingFeeAmount == null ? "" : openingFeeAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getBondAmount() {
- return bondAmount == null ? "" : bondAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getHoldAmount() {
- return holdAmount == null ? "" : holdAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getForceClosingPrice() {
- return forceClosingPrice == null ? "" : forceClosingPrice.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public void setOpeningFeeAmount(BigDecimal openingFeeAmount, BigDecimal feeSpread) {
- this.openingFeeAmount = openingFeeAmount == null ? openingFeeAmount : openingFeeAmount.multiply(feeSpread).setScale(8, BigDecimal.ROUND_DOWN);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/HoldOrderListVo.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/HoldOrderListVo.java
deleted file mode 100644
index e06bff3..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/HoldOrderListVo.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.vo;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * @author wzy
- * @date 2020-06-01
- **/
-@Data
-@ApiModel(value = "HoldOrderListVo", description = "获取当前持仓列表接口返回数据类")
-public class HoldOrderListVo {
-
- @ApiModelProperty(value = "订单ID", example = "1")
- private Long id;
-
- @ApiModelProperty(value = "开仓均价", example = "9000.00")
- private BigDecimal openingPrice;
-
- @ApiModelProperty(value = "止损")
- private BigDecimal stopLossPrice;
-
- @ApiModelProperty(value = "止盈")
- private BigDecimal stopProfitPrice;
-
- @ApiModelProperty(value = "保证金")
- private BigDecimal bondAmount;
-
- @ApiModelProperty(value = "强平价")
- private BigDecimal forceClosingPrice;
-
- @ApiModelProperty(value = "杠杆倍率")
- private int leverRatio;
-
- @ApiModelProperty(value = "订单类型 1-开多 2-开空")
- private int openingType;
-
- @ApiModelProperty(value = "币种")
- private String symbol;
-
- @ApiModelProperty(value = "张数")
- private int symbolCnt;
-
- @ApiModelProperty(value = "回报率")
- private BigDecimal returnRate;
-
- @ApiModelProperty(value = "盈亏")
- private BigDecimal profitOrLoss;
-
- @ApiModelProperty(value = "可增加的最大保证金")
- private BigDecimal canAddMaxBond;
-
- @ApiModelProperty(value = "可减少最大保证金")
- private BigDecimal canReduceMaxBond;
-
- @ApiModelProperty(value = "开仓时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date createTime;
-
- @ApiModelProperty(value = "交易类型 1-市价 2-限价")
- private Integer tradeType;
-
- public String getOpeningPrice() {
- return openingPrice.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getBondAmount() {
- return bondAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getForceClosingPrice() {
- return forceClosingPrice.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getProfitOrLoss() {
- return profitOrLoss.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public BigDecimal getCanAddMaxBond() {
- return canAddMaxBond.setScale(4, BigDecimal.ROUND_DOWN);
- }
-
- public BigDecimal getCanReduceMaxBond() {
- return canReduceMaxBond.setScale(4, BigDecimal.ROUND_DOWN);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/OrderDetailVo.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/OrderDetailVo.java
deleted file mode 100644
index 2939331..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/OrderDetailVo.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.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;
-
-/**
- * @author wzy
- * @date 2020-06-05
- **/
-@Data
-@ApiModel(value = "OrderDetailVo", description = "历史委托订单详情接口返回参数类")
-public class OrderDetailVo {
-
- @ApiModelProperty("交易类型 1-市价2-限价")
- private int tradeType;
-
- @ApiModelProperty("订单类型 -1撤单,1开多,2开空,3平多,4平空")
- private int orderType;
-
- @ApiModelProperty("订单编号")
- private String orderNo;
-
- @ApiModelProperty("委托开仓价")
- private BigDecimal entrustOpeningPrice;
-
- @ApiModelProperty("委托时间")
- private Date entrustTime;
-
- @ApiModelProperty("币种")
- private String symbol;
-
- @ApiModelProperty("张数")
- private int symbolCnt;
-
- @ApiModelProperty("平仓价")
- private BigDecimal closingPrice;
-
- @ApiModelProperty("平仓手续费")
- private BigDecimal closingFeeAmount;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- @ApiModelProperty("平仓时间")
- private Date closingTime;
-
- @ApiModelProperty("平仓类型 2平多3平空4爆仓平多5爆仓平空6止盈平多7止盈平空8止损平多9止损平空")
- private int closingType;
-
- @ApiModelProperty("止损价")
- private BigDecimal stopLossPrice;
-
- @ApiModelProperty("止盈价")
- private BigDecimal stopProfitPrice;
-
- @ApiModelProperty("盈亏金额")
- private BigDecimal rewardAmount;
-
- @ApiModelProperty("盈亏比例")
- private BigDecimal rewardRatio;
-
- @ApiModelProperty("开仓价")
- private BigDecimal openingPrice;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- @ApiModelProperty("开仓时间")
- private Date openingTime;
-
- @ApiModelProperty("开仓手续费")
- private BigDecimal openingFeeAmount;
-
- @ApiModelProperty("保证金")
- private BigDecimal bondAmount;
-
- @ApiModelProperty("持仓费")
- private BigDecimal holdAmount;
-
- @ApiModelProperty("杠杆")
- private int leverRatio;
-
- public String getClosingPrice() {
- return closingPrice == null ? "" : closingPrice.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getClosingFeeAmount() {
- return closingFeeAmount == null ? "" : closingFeeAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getRewardAmount() {
- return rewardAmount == null ? "" : rewardAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getOpeningPrice() {
- return openingPrice == null ? "" : openingPrice.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getOpeningFeeAmount() {
- return openingFeeAmount == null ? "" : openingFeeAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getBondAmount() {
- return bondAmount == null ? "" : bondAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getHoldAmount() {
- return holdAmount == null ? "" : holdAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public void setClosingFeeAmount(BigDecimal closingFeeAmount, BigDecimal feeSpread) {
- this.closingFeeAmount = closingFeeAmount == null ? closingFeeAmount : closingFeeAmount.multiply(feeSpread).setScale(8, BigDecimal.ROUND_DOWN);
- }
-
- public void setOpeningFeeAmount(BigDecimal openingFeeAmount, BigDecimal feeSpread) {
- this.openingFeeAmount = openingFeeAmount == null ? openingFeeAmount : openingFeeAmount.multiply(feeSpread).setScale(8, BigDecimal.ROUND_DOWN);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/OrderListVo.java b/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/OrderListVo.java
deleted file mode 100644
index 24701bb..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/parameter/vo/OrderListVo.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.xcong.excoin.modules.contract.parameter.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;
-
-/**
- * @author wzy
- * @date 2020-06-05
- **/
-@Data
-@ApiModel(value = "OrderListVo", description = "历史委托订单接口返回参数类")
-public class OrderListVo {
-
- @ApiModelProperty("订单ID")
- private Long id;
-
- @ApiModelProperty("订单类型 1开多,2开空,3平多,4平空")
- private int orderType;
-
- @ApiModelProperty("订单状态 1成交 2撤单")
- private int orderStatus;
-
- @ApiModelProperty("开仓均价")
- private BigDecimal openingPrice;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- @ApiModelProperty("开仓价")
- private Date openingTime;
-
- @ApiModelProperty("开仓手续费")
- private BigDecimal openingFeeAmount;
-
- @ApiModelProperty("保证金")
- private BigDecimal bondAmount;
-
- @ApiModelProperty("张数")
- private int symbolCnt;
-
- @ApiModelProperty("已实现盈亏")
- private BigDecimal rewardAmount;
-
- @ApiModelProperty("平仓类型 2平多3平空4爆仓平多5爆仓平空6止盈平多7止盈平空8止损平多9止损平空")
- private int closingType;
-
- @ApiModelProperty("平仓手续费")
- private BigDecimal closingFeeAmount;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- @ApiModelProperty("平仓时间")
- private Date closingTime;
-
- @ApiModelProperty("平仓价格")
- private BigDecimal closingPrice;
-
- @ApiModelProperty("强平价")
- private BigDecimal forceClosingPrice;
-
- @ApiModelProperty(value = "交易类型 1-市价 2-限价")
- private Integer tradeType;
-
- public String getOpeningFeeAmount() {
- return openingFeeAmount == null ? "" : openingFeeAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
-
- public String getClosingFeeAmount() {
- return closingFeeAmount == null ? "" : closingFeeAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getBondAmount() {
- return bondAmount == null ? "" : bondAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-
- public String getRewardAmount() {
- return rewardAmount == null ? "" : rewardAmount.setScale(4, BigDecimal.ROUND_DOWN).toPlainString();
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/ContractEntrustOrderService.java b/src/main/java/com/xcong/excoin/modules/contract/service/ContractEntrustOrderService.java
deleted file mode 100644
index 2e27705..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/ContractEntrustOrderService.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.contract.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.dto.SubmitEntrustDto;
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface ContractEntrustOrderService extends IService<ContractEntrustOrderEntity> {
-
- public Result addContractEntrustOrder(SubmitEntrustDto submitEntrustDto);
-
- public Result findEntrustOrderList(String symbol);
-
- public Result cancelEntrustOrder(Long id);
-
- public List<ContractEntrustOrderEntity> selectEntrustOrderListByIds( List<Long> list);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/ContractHoldOrderService.java b/src/main/java/com/xcong/excoin/modules/contract/service/ContractHoldOrderService.java
deleted file mode 100644
index eb2d903..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/ContractHoldOrderService.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.xcong.excoin.modules.contract.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.dto.*;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface ContractHoldOrderService extends IService<ContractHoldOrderEntity> {
-
- public Result submitOrder(SubmitOrderDto submitOrderDto);
-
- public int updateContractHoldOrderCanNotClosingByIds(List<OrderModel> list, String batchNo);
-
- public List<ContractHoldOrderEntity> selectContractHoldOrderByBatchNo(String batchNo);
-
- public void updateOrderIsCanClosingAndBatchNoById(Long id);
-
- public Result findHoldOrderList(String symbol);
-
- public Result cancelHoldOrder(Long id);
-
- public Result cancelHoldOrderBatch(SymbolDto symbolDto);
-
- public Result setTargetProfitOrLess(ProfitOrLessDto profitOrLessDto);
-
- public Result changeBond(ChangeBondDto changeBondDto);
-
- public Result findContractMoneyInfo(String symbol);
-
- public Result changeLeverRate(ChangeLeverRateDto changeLeverRateDto);
-
- public Result findHoldOrderDetailById(Long id);
-
- public Result findOrderList(OrderListDto orderListDto);
-
- public Result findOrderDetailById(Long id);
-
- public void calHoldOrderHoldFeeAmount();
-
- public void calHoldFeeAmountForBondAmount();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/ContractOrderService.java b/src/main/java/com/xcong/excoin/modules/contract/service/ContractOrderService.java
deleted file mode 100644
index 86cbb33..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/ContractOrderService.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.xcong.excoin.modules.contract.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.dto.SubmitOrderDto;
-
-/**
- * @author helius
- */
-public interface ContractOrderService extends IService<ContractOrderEntity> {
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/RabbitOrderService.java b/src/main/java/com/xcong/excoin/modules/contract/service/RabbitOrderService.java
deleted file mode 100644
index 670735f..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/RabbitOrderService.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.xcong.excoin.modules.contract.service;
-
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface RabbitOrderService {
-
- public void cancelHoldOrder(List<Long> ids);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractEntrustOrderServiceImpl.java b/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractEntrustOrderServiceImpl.java
deleted file mode 100644
index cda4dcf..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractEntrustOrderServiceImpl.java
+++ /dev/null
@@ -1,210 +0,0 @@
-package com.xcong.excoin.modules.contract.service.impl;
-
-import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.enumerates.MemberWalletCoinEnum;
-import com.xcong.excoin.common.enumerates.RabbitPriceTypeEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.service.CommonService;
-import com.xcong.excoin.modules.contract.dao.ContractEntrustOrderDao;
-import com.xcong.excoin.modules.contract.dao.ContractOrderDao;
-import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.mapper.ContractEntrustOrderEntityMapper;
-import com.xcong.excoin.modules.contract.parameter.dto.SubmitEntrustDto;
-import com.xcong.excoin.modules.contract.parameter.dto.SubmitOrderDto;
-import com.xcong.excoin.modules.contract.parameter.vo.ContractEntrustVo;
-import com.xcong.excoin.modules.contract.service.ContractEntrustOrderService;
-import com.xcong.excoin.modules.contract.service.ContractHoldOrderService;
-import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import com.xcong.excoin.rabbit.producer.OrderProducer;
-import com.xcong.excoin.utils.*;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-27
- **/
-@Slf4j
-@Service
-public class ContractEntrustOrderServiceImpl extends ServiceImpl<ContractEntrustOrderDao, ContractEntrustOrderEntity> implements ContractEntrustOrderService {
-
- @Resource
- private ContractEntrustOrderDao contractEntrustOrderDao;
-
- @Resource
- private MemberWalletContractDao memberWalletContractDao;
-
- @Resource
- private RedisUtils redisUtils;
-
- @Resource
- private CacheSettingUtils cacheSettingUtils;
-
- @Resource
- private ContractOrderDao contractOrderDao;
-
- @Resource
- private CommonService commonService;
-
- @Resource
- private OrderProducer producer;
-
- @Resource
- private ContractHoldOrderService contractHoldOrderService;
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public Result addContractEntrustOrder(SubmitEntrustDto submitEntrustDto) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
-
- // 获取最新价
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(submitEntrustDto.getSymbol())));
-
- // 委托开仓
- if (submitEntrustDto.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_OPEN_MORE || submitEntrustDto.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_OPEN_LESS) {
- // 开多委托价不能大于当前价
- if (submitEntrustDto.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_OPEN_MORE) {
- if (submitEntrustDto.getEntrustPrice().compareTo(newPrice) > -1) {
- SubmitOrderDto submitOrderDto = new SubmitOrderDto();
- submitOrderDto.setOrderType(submitEntrustDto.getEntrustType());
- submitOrderDto.setSymbol(submitEntrustDto.getSymbol());
- submitOrderDto.setSymbolCnt(submitEntrustDto.getSymbolCnt());
- submitOrderDto.setLeverRatio(submitEntrustDto.getLeverRatio());
- return contractHoldOrderService.submitOrder(submitOrderDto);
- }
- }
-
- // 开空委托价不能小于当前价
- if (submitEntrustDto.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_OPEN_LESS) {
- if (submitEntrustDto.getEntrustPrice().compareTo(newPrice) < 1) {
- SubmitOrderDto submitOrderDto = new SubmitOrderDto();
- submitOrderDto.setOrderType(submitEntrustDto.getEntrustType());
- submitOrderDto.setSymbol(submitEntrustDto.getSymbol());
- submitOrderDto.setSymbolCnt(submitEntrustDto.getSymbolCnt());
- submitOrderDto.setLeverRatio(submitEntrustDto.getLeverRatio());
- return contractHoldOrderService.submitOrder(submitOrderDto);
- }
- }
-
- MemberWalletContractEntity walletContract = memberWalletContractDao.selectById(memberEntity.getId());
-
- BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(submitEntrustDto.getSymbol());
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
-
- // 保证金计算 -- 建仓价X规格X手数X(1/杠杆倍率)
- BigDecimal bondAmount = submitEntrustDto.getEntrustPrice().multiply(lotNumber).multiply(new BigDecimal(submitEntrustDto.getSymbolCnt())).multiply((BigDecimal.ONE.divide(BigDecimal.valueOf(submitEntrustDto.getLeverRatio()), 8, BigDecimal.ROUND_DOWN)));
-
- // 开仓手续费 建仓价*规格*手数*手续费率
- BigDecimal openFeePrice = submitEntrustDto.getEntrustPrice().multiply(lotNumber)
- .multiply(new BigDecimal(submitEntrustDto.getSymbolCnt()))
- .multiply(tradeSettingEntity.getFeeRatio().divide(new BigDecimal(100)))
- .setScale(8, BigDecimal.ROUND_DOWN);
- log.info("手续费:{}", openFeePrice);
-
- // 预付款
- BigDecimal entrustTotalAmount = bondAmount.add(openFeePrice).add(openFeePrice);
- log.info("预付款:{}", entrustTotalAmount);
-
- if (entrustTotalAmount.compareTo(walletContract.getAvailableBalance()) > -1) {
- return Result.fail(MessageSourceUtils.getString("member_service_0085"));
- }
-
- ContractEntrustOrderEntityMapper convert = ContractEntrustOrderEntityMapper.INSTANCE;
- ContractEntrustOrderEntity entrustOrderEntity = convert.submitEntrustDtoToEntity(submitEntrustDto);
- entrustOrderEntity.setOrderNo(commonService.generateOrderNo(memberEntity.getId()));
- entrustOrderEntity.setMemberId(memberEntity.getId());
- entrustOrderEntity.setBondAmount(bondAmount.add(openFeePrice));
- entrustOrderEntity.setSymbolSku(lotNumber);
- entrustOrderEntity.setEntrustAmount(entrustTotalAmount);
- // 暂默认逐仓
- entrustOrderEntity.setPositionType(ContractEntrustOrderEntity.POSITION_TYPE_ADD);
-
- int i = contractEntrustOrderDao.insert(entrustOrderEntity);
-
- memberWalletContractDao.increaseWalletContractBalanceById(entrustTotalAmount.negate(), null, entrustOrderEntity.getBondAmount(), walletContract.getId());
- if (i > 0) {
-
- // 发送委托单队列消息
- if (submitEntrustDto.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_OPEN_MORE) {
- OrderModel model = new OrderModel(entrustOrderEntity.getId(), RabbitPriceTypeEnum.ENTRUST_OPEN_MORE.getValue(), submitEntrustDto.getEntrustPrice().setScale(8, RoundingMode.HALF_UP).toPlainString(), submitEntrustDto.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
-
- LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), entrustTotalAmount, walletContract.getAvailableBalance().subtract(entrustTotalAmount), submitEntrustDto.getSymbol(), "委托买涨", "买涨:" + submitEntrustDto.getSymbol());
- } else {
- OrderModel model = new OrderModel(entrustOrderEntity.getId(), RabbitPriceTypeEnum.ENTRUST_OPEN_LESS.getValue(), submitEntrustDto.getEntrustPrice().setScale(8, RoundingMode.HALF_UP).toPlainString(), submitEntrustDto.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
-
- LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), entrustTotalAmount, walletContract.getAvailableBalance().subtract(entrustTotalAmount), submitEntrustDto.getSymbol(), "委托买跌", "买跌:" + submitEntrustDto.getSymbol());
- }
-
- return Result.ok(MessageSourceUtils.getString("result_success_msg"));
- } else {
- return Result.fail(MessageSourceUtils.getString("result_fail_msg"));
- }
- }
-
- // 委托平仓 (全仓模式)
- if (submitEntrustDto.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_CLOSE_MORE || submitEntrustDto.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_CLOSE_LESS) {
- return Result.fail("功能暂未开放,敬请期待");
- }
-
- return Result.fail(MessageSourceUtils.getString("result_fail_msg"));
- }
-
- @Override
- public Result findEntrustOrderList(String symbol) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- List<ContractEntrustOrderEntity> list = contractEntrustOrderDao.selectEntrustOrderListByMemberIdAndSymbol(memberEntity.getId(), symbol);
- List<ContractEntrustVo> resultList = ContractEntrustOrderEntityMapper.INSTANCE.entityListToVoList(list);
- return Result.ok(resultList);
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Result cancelEntrustOrder(Long id) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
-
- // 查询该委托单是否为该用户所有
- ContractEntrustOrderEntity entrustOrderEntity = contractEntrustOrderDao.selectEntrustOrderByIdAndMemberId(id, memberEntity.getId());
- if (entrustOrderEntity == null) {
- return Result.fail(MessageSourceUtils.getString("entrust_order_not_exist"));
- }
-
- MemberWalletContractEntity walletContractEntity = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), MemberWalletCoinEnum.WALLETCOINCODE.getValue());
-
- BigDecimal total = entrustOrderEntity.getEntrustAmount();
- memberWalletContractDao.increaseWalletContractBalanceById(total, null, entrustOrderEntity.getBondAmount().negate(), walletContractEntity.getId());
-
- ContractOrderEntity orderEntity = ContractEntrustOrderEntityMapper.INSTANCE.entrustOrderToOrder(entrustOrderEntity);
- orderEntity.setTradeType(ContractOrderEntity.TRADE_TYPE_MARK_PRICE);
- orderEntity.setOrderStatus(ContractOrderEntity.ORDER_STATUS_CANCEL);
- int i = contractOrderDao.insert(orderEntity);
-
- contractEntrustOrderDao.deleteById(entrustOrderEntity.getId());
-
- // 插入财务流水
- LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), total, walletContractEntity.getAvailableBalance().add(total), entrustOrderEntity.getSymbol(), "撤销委托单", "撤销委托单");
- if (i > 0) {
- return Result.ok(MessageSourceUtils.getString("cancellation_success"));
- }
- return Result.fail(MessageSourceUtils.getString("cancellation_fail"));
- }
-
- @Override
- public List<ContractEntrustOrderEntity> selectEntrustOrderListByIds(List<Long> list) {
- return contractEntrustOrderDao.selectEntrustOrderListByIds(list);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java b/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java
deleted file mode 100644
index dcbb704..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java
+++ /dev/null
@@ -1,710 +0,0 @@
-package com.xcong.excoin.modules.contract.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import com.alibaba.druid.sql.visitor.functions.If;
-import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.common.enumerates.RabbitPriceTypeEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.service.CommonService;
-import com.xcong.excoin.modules.contract.dao.ContractEntrustOrderDao;
-import com.xcong.excoin.modules.contract.dao.ContractHoldOrderDao;
-import com.xcong.excoin.modules.contract.dao.ContractOrderDao;
-import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.mapper.ContractHoldOrderEntityMapper;
-import com.xcong.excoin.modules.contract.mapper.ContractOrderEntityMapper;
-import com.xcong.excoin.modules.contract.parameter.dto.*;
-import com.xcong.excoin.modules.contract.parameter.vo.*;
-import com.xcong.excoin.modules.contract.service.ContractHoldOrderService;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.dao.MemberLevelRateDao;
-import com.xcong.excoin.modules.member.dao.MemberSettingDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
-import com.xcong.excoin.modules.member.entity.*;
-import com.xcong.excoin.modules.platform.dao.TradeSettingDao;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import com.xcong.excoin.rabbit.producer.OrderProducer;
-import com.xcong.excoin.utils.*;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import jnr.a64asm.Mem;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import sun.rmi.runtime.Log;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.*;
-
-/**
- * @author wzy
- * @date 2020-05-27
- **/
-@Slf4j
-@Service
-public class ContractHoldOrderServiceImpl extends ServiceImpl<ContractHoldOrderDao, ContractHoldOrderEntity> implements ContractHoldOrderService {
-
- @Resource
- private ContractHoldOrderDao contractHoldOrderDao;
-
- @Resource
- private ContractOrderDao contractOrderDao;
-
- @Resource
- private ContractEntrustOrderDao contractEntrustOrderDao;
-
- @Resource
- private CommonService commonService;
-
- @Resource
- private MemberWalletContractDao memberWalletContractDao;
-
- @Resource
- private MemberLevelRateDao memberLevelRateDao;
-
- @Resource
- private CacheSettingUtils cacheSettingUtils;
-
- @Resource
- private RedisUtils redisUtils;
-
- @Resource
- private OrderProducer producer;
-
- @Resource
- private MemberDao memberDao;
- @Resource
- private MemberSettingDao memberSettingDao;
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public Result submitOrder(SubmitOrderDto submitOrderDto) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
-
- // 获取最新价
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(submitOrderDto.getSymbol())));
-
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), CoinTypeEnum.USDT.name());
-
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
-
- MemberSettingEntity memberSetting = memberSettingDao.selectMemberSettingByMemberId(memberEntity.getId());
- BigDecimal spread = memberSetting.getSpread();
- // 规格
- BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(submitOrderDto.getSymbol());
-
- // 开仓价
- BigDecimal openingPrice = BigDecimal.ZERO;
-
- // 开多
- if (submitOrderDto.getOrderType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
- // 市场价*(1 + (点差/10000))
- openingPrice = newPrice.multiply(BigDecimal.ONE.add(spread.divide(new BigDecimal(10000)))).setScale(8, BigDecimal.ROUND_DOWN);
-
- // 开空
- } else if (submitOrderDto.getOrderType() == ContractHoldOrderEntity.OPENING_TYPE_LESS) {
- // 市场价*(1 - (点差/10000))
- openingPrice = newPrice.multiply(BigDecimal.ONE.subtract(spread.divide(new BigDecimal(10000)))).setScale(8, BigDecimal.ROUND_DOWN);
- } else {
- return Result.fail("未知类型");
- }
-
- log.info("开仓价:{}", openingPrice);
- // 开仓手续费 建仓价*规格*手数*手续费率
- BigDecimal openFeePrice = openingPrice.multiply(lotNumber)
- .multiply(new BigDecimal(submitOrderDto.getSymbolCnt()))
- .multiply(tradeSettingEntity.getFeeRatio().divide(new BigDecimal(100)))
- .setScale(8, BigDecimal.ROUND_DOWN);
- log.info("开仓手续费:{}", openFeePrice);
-
- // 保证金 建仓价*规格*手数*(1/杠杆倍率)
- BigDecimal bondAmount = openingPrice.multiply(lotNumber).multiply(new BigDecimal(submitOrderDto.getSymbolCnt()))
- .multiply(BigDecimal.ONE.divide(new BigDecimal(submitOrderDto.getLeverRatio())))
- .setScale(8, BigDecimal.ROUND_DOWN);
- log.info("保证金:{}", bondAmount);
-
- // 预付款为 --> 保证金+开仓手续费+平仓手续费 (开仓平仓手续费相同)
- BigDecimal prePaymentAmount = bondAmount.add(openFeePrice).add(openFeePrice);
- log.info("预付款:{}", prePaymentAmount);
-
- if (prePaymentAmount.compareTo(walletContract.getAvailableBalance()) > -1) {
- return Result.fail("可用金额不足");
- }
-
- // 预估强平价
- BigDecimal forceClosingPrice = CalculateUtil.getForceSetPrice(bondAmount, openingPrice, submitOrderDto.getSymbolCnt(), lotNumber, submitOrderDto.getOrderType(), memberEntity);
- log.info("强平价:{}", forceClosingPrice);
-
- ContractHoldOrderEntity holdOrderEntity = new ContractHoldOrderEntity();
- holdOrderEntity.setMemberId(memberEntity.getId());
- holdOrderEntity.setOrderNo(commonService.generateOrderNo(memberEntity.getId()));
- holdOrderEntity.setPositionType(ContractEntrustOrderEntity.POSITION_TYPE_ADD);
- holdOrderEntity.setTradeType(ContractHoldOrderEntity.TRADE_TYPE_MARK);
- holdOrderEntity.setSymbol(submitOrderDto.getSymbol());
- holdOrderEntity.setSymbolCnt(submitOrderDto.getSymbolCnt());
- holdOrderEntity.setSymbolSku(lotNumber);
- holdOrderEntity.setLeverRatio(submitOrderDto.getLeverRatio());
- holdOrderEntity.setForceClosingPrice(forceClosingPrice);
- holdOrderEntity.setOpeningFeeAmount(openFeePrice);
- holdOrderEntity.setOpeningPrice(openingPrice);
- holdOrderEntity.setOpeningType(submitOrderDto.getOrderType());
- holdOrderEntity.setMarkPrice(newPrice);
- holdOrderEntity.setIsCanClosing(ContractHoldOrderEntity.ORDER_CAN_CLOSING_Y);
- holdOrderEntity.setPrePaymentAmount(prePaymentAmount);
- holdOrderEntity.setBondAmount(bondAmount.add(openFeePrice));
- holdOrderEntity.setOperateNo(1);
-
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity);
- contractOrderEntity.setOpeningTime(new Date());
- contractHoldOrderDao.insert(holdOrderEntity);
- int i = contractOrderDao.insert(contractOrderEntity);
-
- if (i > 0) {
- memberWalletContractDao.increaseWalletContractBalanceById(prePaymentAmount.negate(), openFeePrice.negate(), null, walletContract.getId());
-
- // 发送爆仓消息
- sendOrderBombMsg(holdOrderEntity.getId(), holdOrderEntity.getOpeningType(), forceClosingPrice, holdOrderEntity.getSymbol(), holdOrderEntity.getOperateNo());
-
- // 计算佣金
- ThreadPoolUtils.calReturnMoney(memberEntity.getId(), contractOrderEntity.getOpeningFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_OPEN);
-
- // 插入财务流水
- if (submitOrderDto.getOrderType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
- LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), submitOrderDto.getSymbol(), "买涨持仓", "买涨:" + submitOrderDto.getSymbol());
- } else {
- LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), submitOrderDto.getSymbol(), "买跌持仓", "买跌:" + submitOrderDto.getSymbol());
- }
- return Result.ok("提交成功");
- }
- return Result.fail("提交失败");
- }
-
- @Override
- public int updateContractHoldOrderCanNotClosingByIds(List<OrderModel> list, String batchNo) {
- return contractHoldOrderDao.updateContractHoldOrderCanNotClosingByIds(list, batchNo);
- }
-
- @Override
- public List<ContractHoldOrderEntity> selectContractHoldOrderByBatchNo(String batchNo) {
- return contractHoldOrderDao.selectContractHoldOrderByBatchNo(batchNo);
- }
-
- @Override
- public void updateOrderIsCanClosingAndBatchNoById(Long id) {
- contractHoldOrderDao.updateOrderIsCanClosingAndBatchNoById(id);
- }
-
- @Override
- public Result findHoldOrderList(String symbol) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
-
- List<ContractHoldOrderEntity> list = contractHoldOrderDao.selectHoldOrderListByMemberIdAndSymbol(memberEntity.getId(), symbol);
- MemberWalletContractEntity walletContractEntity = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), CoinTypeEnum.USDT.name());
- if (CollUtil.isNotEmpty(list)) {
- BigDecimal totalProfitOrLoss = BigDecimal.ZERO;
- List<HoldOrderListVo> resultList = new ArrayList<>();
- for (ContractHoldOrderEntity holdOrderEntity : list) {
- HoldOrderListVo holdOrderListVo = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToDto(holdOrderEntity);
- // 获取最新价
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(holdOrderEntity.getSymbol())));
- BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(holdOrderEntity.getSymbol());
- // 盈亏
- BigDecimal rewardRatio = BigDecimal.ZERO;
- // 开多
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
- // (最新价-开仓价)*规格*张数
- rewardRatio = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
- // 开空
- } else {
- // (开仓价-最新价)*规格*张数
- rewardRatio = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
- }
-
- if (memberEntity.getIsProfit() == MemberEntity.IS_PROFIT_Y) {
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
- if (rewardRatio.compareTo(BigDecimal.ZERO) > -1) {
- rewardRatio = rewardRatio.multiply(BigDecimal.ONE.subtract(tradeSettingEntity.getProfitParam()));
- } else {
-// rewardRatio = rewardRatio.multiply(BigDecimal.ONE.add(tradeSettingEntity.getProfitParam()));
- }
- }
-
- // 回报率
- BigDecimal returnRate = rewardRatio.divide(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), 8, BigDecimal.ROUND_DOWN);
-
- // 成本价格
- BigDecimal costPrice = holdOrderEntity.getOpeningPrice()
- .multiply(lotNumber)
- .multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()))
- .divide(new BigDecimal(holdOrderEntity.getLeverRatio()), 8, BigDecimal.ROUND_DOWN);
-
- // 可增加最大保证金
-// BigDecimal canAddMaxBond = holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()).subtract(costPrice);
-// if (canAddMaxBond.compareTo(BigDecimal.ZERO) < 0) {
-// canAddMaxBond = BigDecimal.ZERO;
-// }
- BigDecimal canReduceMaxBond = holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getPrePaymentAmount());
-
- if (rewardRatio.compareTo(BigDecimal.ZERO) < 0) {
- canReduceMaxBond = canReduceMaxBond.add(rewardRatio);
- }
-
- if (canReduceMaxBond.compareTo(BigDecimal.ZERO) < 0) {
- canReduceMaxBond = BigDecimal.ZERO;
- }
-
- holdOrderListVo.setCanReduceMaxBond(canReduceMaxBond);
- holdOrderListVo.setCanAddMaxBond(walletContractEntity.getAvailableBalance());
- holdOrderListVo.setReturnRate(returnRate);
- holdOrderListVo.setProfitOrLoss(rewardRatio);
- resultList.add(holdOrderListVo);
- totalProfitOrLoss = totalProfitOrLoss.add(rewardRatio);
- }
-
- Map<String, Object> result = new HashMap<>();
- result.put("hold", resultList);
- result.put("totalProfitOrLoss", totalProfitOrLoss.setScale(4, BigDecimal.ROUND_DOWN).toPlainString());
- return Result.ok(result);
- }
- return Result.ok("success");
- }
-
- @Override
- public Result cancelHoldOrder(Long id) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectHoldOrderByMemberIdAndId(memberEntity.getId(), id);
- if (holdOrderEntity == null) {
- return Result.fail("订单不存在");
- }
-
- if (ContractHoldOrderEntity.ORDER_CAN_CLOSING_N == holdOrderEntity.getIsCanClosing()) {
- return Result.fail("订单暂不可平仓");
- }
-
- contractHoldOrderDao.updateHoldOrderIsCanClosingById(ContractHoldOrderEntity.ORDER_CAN_CLOSING_N, id);
- // 发送平仓消息
- List<Long> ids = new ArrayList<>();
- ids.add(id);
- producer.sendCloseTrade(JSONObject.toJSONString(ids));
-
- return Result.ok("平仓成功");
- }
-
- @Override
- public Result cancelHoldOrderBatch(SymbolDto symbolDto) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- List<ContractHoldOrderEntity> holdOrderEntities = contractHoldOrderDao.selectHoldOrderListByMemberIdAndSymbol(memberEntity.getId(), symbolDto.getSymbol());
- if (CollUtil.isEmpty(holdOrderEntities)) {
- return Result.fail("订单不存在");
- }
-
- List<Long> ids = new ArrayList<>();
- for (ContractHoldOrderEntity holdOrderEntity : holdOrderEntities) {
- contractHoldOrderDao.updateHoldOrderIsCanClosingById(ContractHoldOrderEntity.ORDER_CAN_CLOSING_N, holdOrderEntity.getId());
- ids.add(holdOrderEntity.getId());
- }
- producer.sendCloseTrade(JSONObject.toJSONString(ids));
- return Result.ok("平仓成功");
- }
-
- @Override
- public Result setTargetProfitOrLess(ProfitOrLessDto profitOrLessDto) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectHoldOrderByMemberIdAndId(memberEntity.getId(), profitOrLessDto.getId());
- if (holdOrderEntity == null) {
- return Result.fail("订单不存在");
- }
-
- // 获取最新价
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(holdOrderEntity.getSymbol())));
- // 开仓价
- BigDecimal openPrice = holdOrderEntity.getOpeningPrice();
- // 设置的止盈止损价
- BigDecimal stopProfitPrice = profitOrLessDto.getStopProfitPrice();
-
- BigDecimal stopLessPrice = profitOrLessDto.getStopLessPrice();
-
- // 开多
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
- if (stopProfitPrice != null) {
- // 当前价大于开仓价
- if (newPrice.compareTo(openPrice) > 0) {
- // 如果止盈价小于当前价
- if (stopProfitPrice.compareTo(newPrice) < 0) {
- return Result.fail("止盈价必须高于当前价");
- }
- } else {
- if (stopProfitPrice.compareTo(openPrice) < 0) {
- return Result.fail("止盈价必须高于开仓价");
- }
- }
- }
-
- if (stopLessPrice != null) {
- if (newPrice.compareTo(openPrice) > 0) {
- if (stopLessPrice.compareTo(openPrice) > 0) {
- return Result.fail("止损价必须低于开仓价");
- }
- } else {
- if (stopLessPrice.compareTo(newPrice) > 0) {
- return Result.fail("止损价必须低于当前价");
- }
- }
- }
- // 开空
- } else {
- if (stopProfitPrice != null) {
- if (newPrice.compareTo(openPrice) > 0) {
- if (stopProfitPrice.compareTo(openPrice) > 0) {
- return Result.fail("止盈价必须低于开仓价");
- }
- } else {
- if (stopProfitPrice.compareTo(newPrice) > 0) {
- return Result.fail("止盈价必须低于当前价");
- }
- }
- }
- if (stopLessPrice != null) {
- if (newPrice.compareTo(openPrice) > 0) {
- if (stopLessPrice.compareTo(newPrice) < 0) {
- return Result.fail("止损价必须高于当前价");
- }
- } else {
- if (stopLessPrice.compareTo(openPrice) < 0) {
- return Result.fail("止损价必须高于开仓价");
- }
- }
- }
- }
-
- holdOrderEntity.setStopProfitPrice(stopProfitPrice);
- holdOrderEntity.setStopLossPrice(stopLessPrice);
-
- int i = contractHoldOrderDao.updateById(holdOrderEntity);
- if (i > 0) {
- OrderModel model = null;
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
- // 开多止盈
- if (stopProfitPrice != null) {
- model = new OrderModel(holdOrderEntity.getId(), RabbitPriceTypeEnum.CLOSE_MORE_STOP_PROFIT.getValue(), stopProfitPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), holdOrderEntity.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- // 开多止损
- if (stopLessPrice != null) {
- model = new OrderModel(holdOrderEntity.getId(), RabbitPriceTypeEnum.CLOSE_MORE_STOP_LESS.getValue(), stopLessPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), holdOrderEntity.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- } else {
- // 开空止盈
- if (stopProfitPrice != null) {
- model = new OrderModel(holdOrderEntity.getId(), RabbitPriceTypeEnum.CLOSE_LESS_STOP_PROFIT.getValue(), stopProfitPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), holdOrderEntity.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- // 开空止损
- if (stopLessPrice != null) {
- model = new OrderModel(holdOrderEntity.getId(), RabbitPriceTypeEnum.CLOSE_LESS_STOP_LESS.getValue(), stopLessPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), holdOrderEntity.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- }
- return Result.ok("设置成功");
- }
- return Result.fail("设置失败");
- }
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public Result changeBond(ChangeBondDto changeBondDto) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectHoldOrderByMemberIdAndId(memberEntity.getId(), changeBondDto.getId());
- if (holdOrderEntity == null) {
- return Result.fail("订单不存在");
- }
-
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), CoinTypeEnum.USDT.name());
-
- // 增加保证金
- if (ChangeBondDto.TYPE_ADD == changeBondDto.getType()) {
- if (changeBondDto.getAmount().compareTo(walletContract.getAvailableBalance()) > 0) {
- return Result.fail("可用余额不足");
- }
- memberWalletContractDao.increaseWalletContractBalanceById(changeBondDto.getAmount().negate(), null, null, walletContract.getId());
- holdOrderEntity.setBondAmount(holdOrderEntity.getBondAmount().add(changeBondDto.getAmount()));
- // 减少保证金
- } else {
- if (holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getPrePaymentAmount()).subtract(changeBondDto.getAmount()).compareTo(BigDecimal.ZERO) < 0) {
- return Result.fail("超出保证金最大减少金额");
- }
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(holdOrderEntity.getSymbol())));
-
- BigDecimal rewardRatio = BigDecimal.ZERO;
- // 开多
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
- // (最新价-开仓价)*规格*张数
- rewardRatio = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(holdOrderEntity.getSymbolSku()).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
- // 开空
- } else {
- // (开仓价-最新价)*规格*张数
- rewardRatio = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(holdOrderEntity.getSymbolSku()).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
- }
-
- if (memberEntity.getIsProfit() == MemberEntity.IS_PROFIT_Y) {
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
- if (rewardRatio.compareTo(BigDecimal.ZERO) > -1) {
- rewardRatio = rewardRatio.multiply(BigDecimal.ONE.subtract(tradeSettingEntity.getProfitParam()));
- }
- }
-
- if (rewardRatio.compareTo(BigDecimal.ZERO) < 0) {
- BigDecimal canReduceMax = holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getPrePaymentAmount()).add(rewardRatio);
- if (canReduceMax.subtract(changeBondDto.getAmount()).compareTo(BigDecimal.ZERO) < 0) {
- return Result.fail("超出保证金最大减少金额");
- }
- }
-
- memberWalletContractDao.increaseWalletContractBalanceById(changeBondDto.getAmount(), null, null, walletContract.getId());
- holdOrderEntity.setBondAmount(holdOrderEntity.getBondAmount().subtract(changeBondDto.getAmount()));
- }
-
- BigDecimal forceClosingPrice = CalculateUtil.getForceSetPrice(holdOrderEntity.getBondAmount(), holdOrderEntity.getOpeningPrice(), holdOrderEntity.getSymbolCnt(), holdOrderEntity.getSymbolSku(), holdOrderEntity.getOpeningType(), memberEntity);
- holdOrderEntity.setForceClosingPrice(forceClosingPrice);
- holdOrderEntity.setOperateNo(holdOrderEntity.getOperateNo() + 1);
-
- int i = contractHoldOrderDao.updateById(holdOrderEntity);
-
- if (i > 0) {
- // 发送爆仓消息
- sendOrderBombMsg(holdOrderEntity.getId(), holdOrderEntity.getOpeningType(), forceClosingPrice, holdOrderEntity.getSymbol(), holdOrderEntity.getOperateNo());
- return Result.ok("调整成功");
- }
- return Result.fail("调整失败");
- }
-
- @Override
- public Result findContractMoneyInfo(String symbol) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
-
- PlatformTradeSettingEntity tradeSetting = cacheSettingUtils.getTradeSetting();
- BigDecimal newPriceSymbol = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol)));
-
- // 当前合约委托单
- List<ContractEntrustOrderEntity> entrustOrderEntities = contractEntrustOrderDao.selectEntrustOrderListByMemberId(memberEntity.getId());
-
- // 当前持仓列表
- List<ContractHoldOrderEntity> holdOrderEntities = contractHoldOrderDao.selectHoldOrderListByMemberId(memberEntity.getId());
-
- // 冻结保证金 -- 即委托单中的保证金之和
- BigDecimal frozenBondAmount = BigDecimal.ZERO;
- if (CollUtil.isNotEmpty(entrustOrderEntities)) {
- for (ContractEntrustOrderEntity entrustOrderEntity : entrustOrderEntities) {
- frozenBondAmount = frozenBondAmount.add(entrustOrderEntity.getBondAmount());
- }
- }
-
- // 占用保证金 -- 即持仓单中的保证金之和
- BigDecimal beUsedBondAmount = BigDecimal.ZERO;
- // 总盈利
- BigDecimal totalProfitOrLess = BigDecimal.ZERO;
- if (CollUtil.isNotEmpty(holdOrderEntities)) {
- for (ContractHoldOrderEntity holdOrderEntity : holdOrderEntities) {
- // 获取最新价
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(holdOrderEntity.getSymbol())));
- BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(holdOrderEntity.getSymbol());
- beUsedBondAmount = beUsedBondAmount.add(holdOrderEntity.getBondAmount());
-
- // 单个订单盈利
- BigDecimal profitOrLess = BigDecimal.ZERO;
- // 开多
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
- profitOrLess = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt())).multiply(lotNumber);
- // 开空
- } else {
- profitOrLess = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt())).multiply(lotNumber);
- }
-
- if (MemberEntity.IS_PROFIT_Y == memberEntity.getIsProfit()) {
- if (profitOrLess.compareTo(BigDecimal.ZERO) > 0) {
- profitOrLess = profitOrLess.multiply(BigDecimal.ONE.subtract(tradeSetting.getForceParam()));
- } else {
- profitOrLess = profitOrLess.multiply(BigDecimal.ONE.add(tradeSetting.getForceParam()));
- }
- }
-
- totalProfitOrLess = totalProfitOrLess.add(profitOrLess);
- }
- }
-
- MemberWalletContractEntity walletContractEntity = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), CoinTypeEnum.USDT.name());
-
- MemberLevelRateEntity rateEntity = memberLevelRateDao.selectLeverRateByMemberIdAndSymbol(memberEntity.getId(), symbol);
-
- // 权益
- BigDecimal equity = walletContractEntity.getTotalBalance().add(totalProfitOrLess);
-
- ContractMoneyInfoVo contractMoneyInfoVo = new ContractMoneyInfoVo();
- contractMoneyInfoVo.setAvailableBalance(walletContractEntity.getAvailableBalance());
- contractMoneyInfoVo.setBeUsedBondAmount(beUsedBondAmount);
- contractMoneyInfoVo.setFrozenBondAmount(frozenBondAmount);
- contractMoneyInfoVo.setEquity(equity);
- contractMoneyInfoVo.setFeeRatio(tradeSetting.getFeeRatio());
- contractMoneyInfoVo.setLeverAgeRatio(tradeSetting.getLeverageRatio());
- contractMoneyInfoVo.setNewPrice(newPriceSymbol);
- contractMoneyInfoVo.setSymbolSku(cacheSettingUtils.getSymbolSku(symbol));
- contractMoneyInfoVo.setLeverRate(rateEntity.getLevelRateUp());
- return Result.ok(contractMoneyInfoVo);
- }
-
- @Override
- public Result changeLeverRate(ChangeLeverRateDto changeLeverRateDto) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- MemberLevelRateEntity levelRateEntity = memberLevelRateDao.selectLeverRateByMemberIdAndSymbol(memberEntity.getId(), changeLeverRateDto.getSymbol());
- levelRateEntity.setLevelRateUp(changeLeverRateDto.getLeverRate());
- levelRateEntity.setLevelRateDown(changeLeverRateDto.getLeverRate());
- int i = memberLevelRateDao.updateById(levelRateEntity);
- if (i > 0) {
- return Result.ok("调整成功");
- }
- return Result.fail("调整失败");
- }
-
- @Override
- public Result findHoldOrderDetailById(Long id) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectHoldOrderByMemberIdAndId(memberEntity.getId(), id);
- if (holdOrderEntity == null) {
- return Result.fail("订单不存在");
- }
-
- HoldOrderDetailVo holdOrderDetailVo = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrderDetailVo(holdOrderEntity);
- BigDecimal feeSpread = cacheSettingUtils.getTradeSetting().getFeeSpreadRatio();
-// holdOrderDetailVo.setOpeningFeeAmount(holdOrderDetailVo.getOpeningFeeAmount().multiply(feeSpread).setScale(8, BigDecimal.ROUND_DOWN));
- holdOrderDetailVo.setOpeningFeeAmount(holdOrderEntity.getOpeningFeeAmount(), feeSpread);
- return Result.ok(holdOrderDetailVo);
- }
-
- @Override
- public Result findOrderList(OrderListDto orderListDto) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- Page<ContractOrderEntity> page = new Page<>(orderListDto.getPageNum(), orderListDto.getPageSize());
- ContractOrderEntity contractOrderEntity = new ContractOrderEntity();
- contractOrderEntity.setMemberId(memberEntity.getId());
- contractOrderEntity.setSymbol(orderListDto.getSymbol());
- IPage<ContractOrderEntity> list = contractOrderDao.selectContractOrderInPage(page, contractOrderEntity);
- Page<OrderListVo> result = ContractOrderEntityMapper.INSTANCE.pageEntityToPageVo(list);
- return Result.ok(result);
- }
-
- @Override
- public Result findOrderDetailById(Long id) {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
- ContractOrderEntity contractOrderEntity = contractOrderDao.selectOrderDetailByIdAndMemberId(id, memberEntity.getId());
- if (contractOrderEntity == null) {
- return Result.fail("订单不存在");
- }
-
- OrderDetailVo orderDetailVo = ContractOrderEntityMapper.INSTANCE.entityToDetailVo(contractOrderEntity);
- BigDecimal feeSpread = cacheSettingUtils.getTradeSetting().getFeeSpreadRatio();
-// orderDetailVo.setClosingFeeAmount(orderDetailVo.getClosingFeeAmount() == null ? orderDetailVo.getClosingFeeAmount() : orderDetailVo.getClosingFeeAmount().multiply(feeSpread).setScale(8, BigDecimal.ROUND_DOWN));
-// orderDetailVo.setOpeningFeeAmount(orderDetailVo.getOpeningFeeAmount() == null ? orderDetailVo.getOpeningFeeAmount() : orderDetailVo.getOpeningFeeAmount().multiply(feeSpread).setScale(8, BigDecimal.ROUND_DOWN));
- orderDetailVo.setOpeningFeeAmount(contractOrderEntity.getOpeningFeeAmount(), feeSpread);
- orderDetailVo.setClosingFeeAmount(contractOrderEntity.getClosingFeeAmount(), feeSpread);
- return Result.ok(orderDetailVo);
- }
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void calHoldOrderHoldFeeAmount() {
- List<ContractHoldOrderEntity> list = contractHoldOrderDao.selectAllHoldOrder();
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
-
- if (CollUtil.isNotEmpty(list)) {
- for (ContractHoldOrderEntity holdOrderEntity : list) {
- BigDecimal holdAmount = holdOrderEntity.getHoldAmount();
- if (holdAmount == null) {
- holdAmount = BigDecimal.ZERO;
- }
-
- BigDecimal thisTimeHold = holdOrderEntity.getBondAmount().multiply(tradeSettingEntity.getDoingRatio());
- log.info("订单编号:{}, 持仓费:{}", holdOrderEntity.getOrderNo(), thisTimeHold);
- MemberWalletContractEntity walletContractEntity = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(holdOrderEntity.getMemberId(), CoinTypeEnum.USDT.name());
-
- // 判断当前可用余额是否大于目前持仓费,若大于则扣可用余额,若小于则扣保证金中的金额
- if (thisTimeHold.compareTo(walletContractEntity.getAvailableBalance()) < 0) {
- memberWalletContractDao.increaseWalletContractBalanceById(thisTimeHold.negate(), thisTimeHold.negate(), null, walletContractEntity.getId());
-
- holdOrderEntity.setHoldAmount(holdAmount.add(thisTimeHold));
- contractHoldOrderDao.updateById(holdOrderEntity);
- } else {
- BigDecimal available = walletContractEntity.getAvailableBalance();
- BigDecimal lessAmount = thisTimeHold.subtract(available);
- MemberEntity memberEntity = memberDao.selectById(holdOrderEntity.getMemberId());
- memberWalletContractDao.increaseWalletContractBalanceById(available.negate(), available.negate(), null, walletContractEntity.getId());
-
- BigDecimal newBondAmount = holdOrderEntity.getBondAmount().subtract(lessAmount);
-
- BigDecimal newForcePrice = CalculateUtil.getForceSetPrice(newBondAmount.subtract(holdOrderEntity.getOpeningFeeAmount()), holdOrderEntity.getOpeningPrice(), holdOrderEntity.getSymbolCnt(), holdOrderEntity.getSymbolSku(), holdOrderEntity.getOpeningType(), memberEntity);
-
- holdOrderEntity.setHoldAmount(holdAmount.add(thisTimeHold));
- holdOrderEntity.setBondAmount(newBondAmount);
- holdOrderEntity.setForceClosingPrice(newForcePrice);
- holdOrderEntity.setOperateNo(holdOrderEntity.getOperateNo() + 1);
- contractHoldOrderDao.updateById(holdOrderEntity);
-
- // 发送爆仓消息
- sendOrderBombMsg(holdOrderEntity.getId(), holdOrderEntity.getOpeningType(), newForcePrice, holdOrderEntity.getSymbol(), holdOrderEntity.getOperateNo());
- }
- }
- }
- }
-
- public void sendOrderBombMsg(Long id, int type, BigDecimal forceClosingPrice, String symbol, int operateNo) {
- OrderModel model = null;
- // 开多
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == type) {
- model = new OrderModel(id, RabbitPriceTypeEnum.CLOSE_MORE_BOMB.getValue(), forceClosingPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), symbol, operateNo);
- // 开空
- } else {
- model = new OrderModel(id, RabbitPriceTypeEnum.CLOSE_LESS_BOMB.getValue(), forceClosingPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), symbol, operateNo);
- }
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void calHoldFeeAmountForBondAmount() {
- List<ContractHoldOrderEntity> list = contractHoldOrderDao.selectAllHoldOrder();
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
-
- if (CollUtil.isNotEmpty(list)) {
- for (ContractHoldOrderEntity holdOrderEntity : list) {
- BigDecimal holdAmount = holdOrderEntity.getHoldAmount();
- if (holdAmount == null) {
- holdAmount = BigDecimal.ZERO;
- }
-
- BigDecimal thisTimeHold = holdOrderEntity.getBondAmount().multiply(tradeSettingEntity.getDoingRatio());
- log.info("订单编号:{}, 持仓费:{}", holdOrderEntity.getOrderNo(), thisTimeHold);
-
- MemberEntity memberEntity = memberDao.selectById(holdOrderEntity.getMemberId());
- BigDecimal subBond = holdOrderEntity.getBondAmount().subtract(thisTimeHold);
-
- BigDecimal newForcePrice = CalculateUtil.getForceSetPrice(subBond.subtract(holdOrderEntity.getOpeningFeeAmount()), holdOrderEntity.getOpeningPrice(), holdOrderEntity.getSymbolCnt(), holdOrderEntity.getSymbolSku(), holdOrderEntity.getOpeningType(), memberEntity);
- holdAmount = holdAmount.add(thisTimeHold);
- holdOrderEntity.setBondAmount(subBond);
- holdOrderEntity.setHoldAmount(holdAmount);
- holdOrderEntity.setForceClosingPrice(newForcePrice);
- holdOrderEntity.setOperateNo(holdOrderEntity.getOperateNo() + 1);
- contractHoldOrderDao.updateById(holdOrderEntity);
-
- // 发送爆仓消息
- sendOrderBombMsg(holdOrderEntity.getId(), holdOrderEntity.getOpeningType(), newForcePrice, holdOrderEntity.getSymbol(), holdOrderEntity.getOperateNo());
- }
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractOrderServiceImpl.java b/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractOrderServiceImpl.java
deleted file mode 100644
index 9fdc086..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractOrderServiceImpl.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.modules.contract.service.impl;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.contract.dao.ContractOrderDao;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.parameter.dto.SubmitOrderDto;
-import com.xcong.excoin.modules.contract.service.ContractOrderService;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.RedisUtils;
-
-import javax.annotation.Resource;
-
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-05-27
- **/
-@Service
-public class ContractOrderServiceImpl extends ServiceImpl<ContractOrderDao, ContractOrderEntity> implements ContractOrderService {
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/impl/OrderWebsocketServiceImpl.java b/src/main/java/com/xcong/excoin/modules/contract/service/impl/OrderWebsocketServiceImpl.java
deleted file mode 100644
index 93b135e..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/impl/OrderWebsocketServiceImpl.java
+++ /dev/null
@@ -1,759 +0,0 @@
-package com.xcong.excoin.modules.contract.service.impl;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.coin.dao.MemberAccountFlowEntityDao;
-import com.xcong.excoin.modules.coin.entity.MemberAccountFlowEntity;
-import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.mapper.ContractEntrustOrderEntityMapper;
-import com.xcong.excoin.modules.contract.mapper.ContractHoldOrderEntityMapper;
-import com.xcong.excoin.modules.contract.service.ContractEntrustOrderService;
-import com.xcong.excoin.modules.contract.service.ContractHoldOrderService;
-import com.xcong.excoin.modules.contract.service.ContractOrderService;
-import com.xcong.excoin.modules.member.dao.AgentReturnDao;
-import com.xcong.excoin.modules.member.dao.MemberSettingDao;
-import com.xcong.excoin.modules.member.entity.AgentReturnEntity;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberSettingEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-import com.xcong.excoin.modules.member.parameter.vo.NeedMoneyMemberVo;
-import com.xcong.excoin.modules.member.service.MemberService;
-import com.xcong.excoin.modules.member.service.MemberWalletContractService;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import com.xcong.excoin.rabbit.producer.OrderProducer;
-import com.xcong.excoin.utils.CacheSettingUtils;
-import com.xcong.excoin.utils.CalculateUtil;
-import com.xcong.excoin.utils.ThreadPoolUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.*;
-
-/**
- * @author helius
- */
-@Slf4j
-@Service
-public class OrderWebsocketServiceImpl {
-
- @Resource
- ContractHoldOrderService contractHoldOrderService;
-
- @Resource
- ContractOrderService contractOrderService;
-
- @Resource
- ContractEntrustOrderService contractEntrustOrderService;
-
- @Resource
- MemberWalletContractService memberWalletContractService;
-
- @Resource
- CacheSettingUtils cacheSettingUtils;
-
- @Resource
- OrderProducer producer;
-
- @Resource
- MemberService memberService;
-
- @Resource
- private AgentReturnDao agentReturnDao;
-
- @Resource
- private MemberAccountFlowEntityDao memberAccountFlowEntityDao;
- @Resource
- private MemberSettingDao memberSettingDao;
-
-
- public void dealOrderFromMq(List<OrderModel> list, Integer type) {
- if (CollectionUtils.isNotEmpty(list)) {
- String batchno = UUID.randomUUID().toString();
- // 更新订单状态
- // 更新为不可平仓状态
- int count = contractHoldOrderService.updateContractHoldOrderCanNotClosingByIds(list, batchno);
- // 查询
- if (count > 0) {
- // 查询
- List<ContractHoldOrderEntity> coinsCoinsOrders = contractHoldOrderService.selectContractHoldOrderByBatchNo(batchno);
- // 根据状态调用不同的方法
- // 1:买入委托2:开多3:开空4:平多5:平空6:爆仓平多7:爆仓平空8:撤单9:止盈平多10:止盈平空11:止损平多12:止损平空
- // 6在这里是爆仓 包括爆空和暴多
- switch (type) {
- case 6:
- this.dealCoinOut(coinsCoinsOrders, list);
- break;
- case 9:
- this.dealForMoreStopPro(coinsCoinsOrders, list);
- break;
- case 10:
- this.dealForLessStopPro(coinsCoinsOrders, list);
- break;
- case 11:
- this.dealForMoreLoss(coinsCoinsOrders, list);
- break;
- case 12:
- this.dealForLessLoss(coinsCoinsOrders, list);
- break;
- default:
- break;
- }
-
- }
-
-
- }
- }
-
- public void dealForLimitMq(List<OrderModel> list) {
- if (CollectionUtils.isNotEmpty(list)) {
- //查询限价委托的单
- String batchno = UUID.randomUUID().toString();
- List<Long> ids = new ArrayList<>();
- list.forEach(model -> ids.add(model.getOrderId()));
- List<ContractEntrustOrderEntity> contractEntrustOrderEntities = contractEntrustOrderService.selectEntrustOrderListByIds(ids);
-
- if (CollectionUtils.isNotEmpty(contractEntrustOrderEntities)) {
- this.dealLimitBuyOrder(contractEntrustOrderEntities);
- }
-
- }
- }
-
- /**
- * 开多止盈
- */
- @Transactional(rollbackFor = Exception.class)
- public void dealForMoreStopPro(List<ContractHoldOrderEntity> orderList, List<OrderModel> list) {
- if (CollectionUtils.isNotEmpty(orderList)) {
- Map<Long, BigDecimal> modelMap = new HashMap<Long, BigDecimal>();
- for (OrderModel model : list) {
- modelMap.put(model.getOrderId(), new BigDecimal(model.getPrice()));
- }
- for (ContractHoldOrderEntity order : orderList) {
- Long orderId = order.getId();
- System.out.println("开多止盈订单号:" + order.getOrderNo());
- System.out.println("传来的止盈价格:" + modelMap.get(order.getId()));
- if (null != order.getStopProfitPrice()) {
- BigDecimal closePrice = order.getStopProfitPrice();
- BigDecimal queuePrice = modelMap.get(order.getId());
- System.out.println("订单的止盈价格:" + closePrice);
- // 判断 保留七位是为了忽略以为小数 防止不精确导致的不相等
- if (queuePrice.compareTo(closePrice) != 0) {
-
- // 不能止盈
- System.out.println("数据库价格:" + queuePrice.toPlainString() + "--价格不能止盈:" + closePrice);
- //更新数据
- contractHoldOrderService.updateOrderIsCanClosingAndBatchNoById(orderId);
- continue;
- }
- System.out.println("执行操作");
- // 止盈价
- String symbol = order.getSymbol();
- // 本次需要退回的保证金
- BigDecimal prePrice = order.getBondAmount();
- Long memberId = order.getMemberId();
- MemberWalletContractEntity wallet = memberWalletContractService.findWalletContractByMemberIdAndSymbol(memberId, "USDT");
- if (wallet != null) {
- // 历史订单
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(order);
- contractOrderEntity.setClosingTime(new Date());
- contractOrderEntity.setId(null);
-
- // 本次平仓数量
- int currentFlat = order.getSymbolCnt();
- BigDecimal symbolSku = cacheSettingUtils.getSymbolSku(order.getSymbol());
- // 盈亏额度= (当前的币种的平仓价-下单时的建仓价)*购买的手数/规格*倍率
- BigDecimal profitLossPrice = (closePrice
- .subtract(order.getOpeningPrice()))
- .multiply(new BigDecimal(currentFlat))
- .multiply(symbolSku).setScale(8, BigDecimal.ROUND_DOWN);
- MemberEntity memberEntity = memberService.getById(memberId);
- MemberSettingEntity memberSettingEntity = memberSettingDao.selectMemberSettingByMemberId(memberId);
- log.info("划点前:{}", profitLossPrice);
- profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.subtract(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_DOWN)));
- log.info("划点后:{}", profitLossPrice);
- if (memberEntity.getIsProfit() == 1) {
- PlatformTradeSettingEntity tradeSetting = cacheSettingUtils.getTradeSetting();
- if (profitLossPrice.compareTo(BigDecimal.ZERO) > 0) {
- profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.subtract(tradeSetting.getProfitParam()));
- } else {
-// profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.add(tradeSetting.getProfitParam()));
- }
- }
- //回报率
- BigDecimal returnRate = profitLossPrice.divide((order.getBondAmount().subtract(contractOrderEntity.getOpeningFeeAmount())), 8, BigDecimal.ROUND_DOWN);
- contractOrderEntity.setRewardAmount(profitLossPrice);
- contractOrderEntity.setRewardRatio(returnRate);
- contractOrderEntity.setClosingFeeAmount(order.getOpeningFeeAmount());
- contractOrderEntity.setClosingPrice(closePrice);
- contractOrderEntity.setClosingType(6);
- contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_MORE);
- BigDecimal totalReturn = BigDecimal.ZERO;
- contractOrderService.save(contractOrderEntity);
-
- contractHoldOrderService.removeById(order.getId());
- // 将需要退回的减去手续费
- BigDecimal needReturn = prePrice.add(profitLossPrice);
- //总退回金额=保证金+收益-手续费
- totalReturn = needReturn.subtract(contractOrderEntity.getClosingFeeAmount());
- // 总的是收益-平仓手续费
- BigDecimal totalBalance = profitLossPrice.subtract(contractOrderEntity.getClosingFeeAmount());
-
- memberWalletContractService.increaseWalletContractBalanceById(totalReturn, totalBalance, null, wallet.getId());
-
- // 流水记录 TODO 531e
- insertAccountFlow(order, wallet, profitLossPrice, "止盈平仓");
-
- //返佣
- ThreadPoolUtils.calReturnMoney(order.getMemberId(), order.getOpeningFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE);
- }
- }
- }
- }
-
- }
-
- /**
- * 开空止盈
- */
- public void dealForLessStopPro(List<ContractHoldOrderEntity> orderList, List<OrderModel> list) {
- //List<CoinsCoinsOrder> orderList = orderMapper.selectOrderByBatchNo(batchno);
- //System.out.println("开空止盈订单batchno:" + batchno);
- if (CollectionUtils.isNotEmpty(orderList)) {
- Map<Long, BigDecimal> modelMap = new HashMap<Long, BigDecimal>();
- for (OrderModel model : list) {
- modelMap.put(model.getOrderId(), new BigDecimal(model.getPrice()));
- }
- for (ContractHoldOrderEntity order : orderList) {
- System.out.println("开空止盈订单号:" + order.getOrderNo());
- System.out.println("传来的止盈价格:" + modelMap.get(order.getId()).toPlainString());
- BigDecimal closePrice = order.getStopProfitPrice();
- Long orderId = order.getId();
- if (null != closePrice) {
-
- // 止盈价
- System.out.println("订单的止盈价格:" + closePrice);
- System.out.println(closePrice.compareTo(modelMap.get(order.getId())));
- BigDecimal queuePrice = modelMap.get(order.getId()).setScale(7, RoundingMode.HALF_UP);
- if (closePrice.compareTo(queuePrice) != 0) {
- System.out.println("数据库价格:" + queuePrice.toPlainString() + "--价格不能开空止盈:" + closePrice);
- contractHoldOrderService.updateOrderIsCanClosingAndBatchNoById(orderId);
- continue;
- }
- System.out.println("执行操作");
- String symbol = order.getSymbol();
- // 本次需要退回的预付款
- BigDecimal prePrice = order.getBondAmount();
- Long memberId = order.getMemberId();
- MemberWalletContractEntity wallet = memberWalletContractService.findWalletContractByMemberIdAndSymbol(memberId, "USDT");
- if (wallet != null) {
- // 历史订单
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(order);
- contractOrderEntity.setClosingTime(new Date());
- contractOrderEntity.setId(null);
-
- // 本次平仓数量
- int currentFlat = order.getSymbolCnt();
- BigDecimal symbolSku = cacheSettingUtils.getSymbolSku(order.getSymbol());
- // 盈亏额度= (当前的币种的平仓价-下单时的建仓价)*购买的手数/规格*倍率
- BigDecimal profitLossPrice = (order.getOpeningPrice()
- .subtract(closePrice))
- .multiply(new BigDecimal(currentFlat + ""))
- .multiply(symbolSku).setScale(8, BigDecimal.ROUND_DOWN);
- MemberEntity memberEntity = memberService.getById(memberId);
- MemberSettingEntity memberSettingEntity = memberSettingDao.selectMemberSettingByMemberId(memberId);
- log.info("划点前:{}", profitLossPrice);
- profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.subtract(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_DOWN)));
- log.info("划点后:{}", profitLossPrice);
- if (memberEntity.getIsProfit() == 1) {
- PlatformTradeSettingEntity tradeSetting = cacheSettingUtils.getTradeSetting();
- if (profitLossPrice.compareTo(BigDecimal.ZERO) > 0) {
- profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.subtract(tradeSetting.getProfitParam()));
- } else {
-// profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.add(tradeSetting.getProfitParam()));
- }
- }
- //回报率
- BigDecimal returnRate = profitLossPrice.divide((order.getBondAmount().subtract(contractOrderEntity.getOpeningFeeAmount())), 8, BigDecimal.ROUND_DOWN);
- contractOrderEntity.setRewardAmount(profitLossPrice);
- contractOrderEntity.setRewardRatio(returnRate);
- contractOrderEntity.setClosingFeeAmount(order.getOpeningFeeAmount());
- contractOrderEntity.setClosingPrice(closePrice);
- contractOrderEntity.setClosingType(7);
- contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_LESS);
- BigDecimal totalReturn = BigDecimal.ZERO;
- contractOrderService.save(contractOrderEntity);
-
- contractHoldOrderService.removeById(order.getId());
- // 将需要退回的减去手续费
- BigDecimal needReturn = prePrice.add(profitLossPrice);
- //总退回金额=保证金+收益-手续费
- totalReturn = needReturn.subtract(contractOrderEntity.getClosingFeeAmount());
- // 更新钱包
- // 总的是收益-平仓手续费
- BigDecimal totalBalance = profitLossPrice.subtract(contractOrderEntity.getClosingFeeAmount());
-
- memberWalletContractService.increaseWalletContractBalanceById(totalReturn, totalBalance, null, wallet.getId());
-
- insertAccountFlow(order, wallet, profitLossPrice, "止盈平仓");
-
- //返佣
- ThreadPoolUtils.calReturnMoney(order.getMemberId(), order.getOpeningFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE);
- }
- }
- }
- }
-
- }
-
- /**
- * 开多止损
- *
- * @param
- */
- public void dealForMoreLoss(List<ContractHoldOrderEntity> orderList, List<OrderModel> list) {
- //List<CoinsCoinsOrder> orderList = orderMapper.selectOrderByBatchNo(batchno);
- //System.out.println("开多止损批次号batchno:" + batchno);
- if (CollectionUtils.isNotEmpty(orderList)) {
- Map<Long, BigDecimal> modelMap = new HashMap<Long, BigDecimal>();
- for (OrderModel model : list) {
- modelMap.put(model.getOrderId(), new BigDecimal(model.getPrice()));
- }
- for (ContractHoldOrderEntity order : orderList) {
- System.out.println("开多止损订单号:" + order.getOrderNo());
- Long orderId = order.getId();
- System.out.println("传来的止损价格:" + modelMap.get(orderId));
-
- if (null != order.getStopLossPrice()) {
- // 止损价
- BigDecimal closePrice = order.getStopLossPrice();
- System.out.println("订单止损价格:" + closePrice.toPlainString());
- BigDecimal queuePrice = modelMap.get(orderId);
- if (closePrice.compareTo(queuePrice) != 0) {
- System.out.println("数据库价格:" + queuePrice.toPlainString() + "--价格不能开多止损:" + closePrice);
- contractHoldOrderService.updateOrderIsCanClosingAndBatchNoById(orderId);
- continue;
- }
- System.out.println("执行操作");
- String symbol = order.getSymbol();
- Long memberId = order.getMemberId();
- // 本次需要退回的预付款
- BigDecimal prePrice = order.getBondAmount();
- MemberWalletContractEntity wallet = memberWalletContractService.findWalletContractByMemberIdAndSymbol(memberId, "USDT");
-
- if (wallet != null) {
- // 历史订单
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(order);
- contractOrderEntity.setClosingTime(new Date());
- contractOrderEntity.setId(null);
-
- // 本次平仓数量
- int currentFlat = order.getSymbolCnt();
- BigDecimal symbolSku = cacheSettingUtils.getSymbolSku(order.getSymbol());
- // 盈亏额度= (当前的币种的平仓价-下单时的建仓价)*购买的手数/规格*倍率
- BigDecimal profitLossPrice = (closePrice
- .subtract(order.getOpeningPrice()))
- .multiply(new BigDecimal(currentFlat + ""))
- .multiply(symbolSku).setScale(8, BigDecimal.ROUND_DOWN);
- MemberEntity memberEntity = memberService.getById(memberId);
-
- if (memberEntity.getIsProfit() == 1) {
- PlatformTradeSettingEntity tradeSetting = cacheSettingUtils.getTradeSetting();
- if (profitLossPrice.compareTo(BigDecimal.ZERO) > 0) {
- profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.subtract(tradeSetting.getProfitParam()));
- } else {
-// profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.add(tradeSetting.getProfitParam()));
- }
- }
- //回报率
- BigDecimal returnRate = profitLossPrice.divide((order.getBondAmount().subtract(contractOrderEntity.getOpeningFeeAmount())), 8, BigDecimal.ROUND_DOWN);
- contractOrderEntity.setRewardAmount(profitLossPrice);
- contractOrderEntity.setRewardRatio(returnRate);
- contractOrderEntity.setClosingFeeAmount(order.getOpeningFeeAmount());
- contractOrderEntity.setClosingPrice(closePrice);
- contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_MORE);
- contractOrderEntity.setClosingType(8);
- BigDecimal totalReturn = BigDecimal.ZERO;
- contractOrderService.save(contractOrderEntity);
-
- contractHoldOrderService.removeById(order.getId());
- // 将需要退回的减去手续费
- BigDecimal needReturn = prePrice.add(profitLossPrice);
- //总退回金额=保证金+收益-手续费
- totalReturn = needReturn.subtract(contractOrderEntity.getClosingFeeAmount());
- // 更新钱包
- // 总的是收益-平仓手续费
- BigDecimal totalBalance = profitLossPrice.subtract(contractOrderEntity.getClosingFeeAmount());
-
- memberWalletContractService.increaseWalletContractBalanceById(totalReturn, totalBalance, null, wallet.getId());
-
- insertAccountFlow(order, wallet, profitLossPrice, "开多止损平仓");
-
- //返佣
- ThreadPoolUtils.calReturnMoney(order.getMemberId(), order.getOpeningFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE);
- }
- }
- }
- }
- }
-
- /**
- * 开空止损
- *
- * @param
- */
- public void dealForLessLoss(List<ContractHoldOrderEntity> orderList, List<OrderModel> list) {
- // List<CoinsCoinsOrder> orderList = orderMapper.selectOrderByBatchNo(batchno);
- //System.out.println("开空止损批次号batchno:" + batchno);
- if (CollectionUtils.isNotEmpty(orderList)) {
- Map<Long, BigDecimal> modelMap = new HashMap<Long, BigDecimal>();
- for (OrderModel model : list) {
- modelMap.put(model.getOrderId(), new BigDecimal(model.getPrice()));
- }
- for (ContractHoldOrderEntity order : orderList) {
- Long orderId = order.getId();
- System.out.println("传来的止损价格:" + modelMap.get(orderId).toPlainString());
- System.out.println("开空止损订单号:" + order.getOrderNo());
- if (null != order.getStopLossPrice()) {
- // 止损价
- BigDecimal closePrice = order.getStopLossPrice();
-
- System.out.println("订单止损价格:" + closePrice.toPlainString());
- BigDecimal queuePrice = modelMap.get(orderId);
- if (closePrice.compareTo(queuePrice) != 0) {
- System.out.println("数据库价格:" + queuePrice.toPlainString() + "--价格不能开空止损:" + closePrice);
- contractHoldOrderService.updateOrderIsCanClosingAndBatchNoById(orderId);
- continue;
- }
- System.out.println("执行操作");
- String symbol = order.getSymbol();
- Long memberId = order.getMemberId();
- // 本次需要退回的预付款
- BigDecimal prePrice = order.getBondAmount();
- MemberWalletContractEntity wallet = memberWalletContractService.findWalletContractByMemberIdAndSymbol(memberId, "USDT");
-
- if (wallet != null) {
- // 历史订单
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(order);
- contractOrderEntity.setClosingTime(new Date());
- contractOrderEntity.setId(null);
-
- // 本次平仓数量
- int currentFlat = order.getSymbolCnt();
- BigDecimal symbolSku = cacheSettingUtils.getSymbolSku(order.getSymbol());
- // 盈亏额度= (当前的币种的平仓价-下单时的建仓价)*购买的手数/规格*倍率
- BigDecimal profitLossPrice = (order.getOpeningPrice()
- .subtract(closePrice))
- .multiply(new BigDecimal(currentFlat + ""))
- .multiply(symbolSku).setScale(8, BigDecimal.ROUND_DOWN);
- MemberEntity memberEntity = memberService.getById(memberId);
-
- if (memberEntity.getIsProfit() == 1) {
- PlatformTradeSettingEntity tradeSetting = cacheSettingUtils.getTradeSetting();
- if (profitLossPrice.compareTo(BigDecimal.ZERO) > 0) {
- profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.subtract(tradeSetting.getProfitParam()));
- } else {
-// profitLossPrice = profitLossPrice.multiply(BigDecimal.ONE.add(tradeSetting.getProfitParam()));
- }
- }
- //回报率
- BigDecimal returnRate = profitLossPrice.divide((order.getBondAmount().subtract(contractOrderEntity.getOpeningFeeAmount())), 8, BigDecimal.ROUND_DOWN);
- contractOrderEntity.setRewardAmount(profitLossPrice);
- contractOrderEntity.setRewardRatio(returnRate);
- contractOrderEntity.setClosingFeeAmount(order.getOpeningFeeAmount());
- contractOrderEntity.setClosingPrice(closePrice);
- contractOrderEntity.setClosingType(9);
- contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_LESS);
- BigDecimal totalReturn = BigDecimal.ZERO;
- contractOrderService.save(contractOrderEntity);
-
- contractHoldOrderService.removeById(order.getId());
-
- // 将需要退回的减去手续费
- BigDecimal needReturn = prePrice.add(profitLossPrice);
- //总退回金额=保证金+收益-手续费
- totalReturn = needReturn.subtract(contractOrderEntity.getClosingFeeAmount());
- // 更新钱包
- // 总的是收益-平仓手续费
- BigDecimal totalBalance = profitLossPrice.subtract(contractOrderEntity.getClosingFeeAmount());
- memberWalletContractService.increaseWalletContractBalanceById(totalReturn, totalBalance, null, wallet.getId());
-
- insertAccountFlow(order, wallet, profitLossPrice, "开空止损平仓");
-
- //返佣
- ThreadPoolUtils.calReturnMoney(order.getMemberId(), order.getOpeningFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE);
- }
- }
- }
- }
- }
-
- private void insertAccountFlow(ContractHoldOrderEntity order, MemberWalletContractEntity wallet, BigDecimal profitLossPrice, String source) {
- MemberAccountFlowEntity record = new MemberAccountFlowEntity();
- record.setCreateTime(new Date());
- record.setSource(source);
- record.setRemark(source);
- record.setBalance(wallet.getAvailableBalance());
- record.setMemberId(order.getMemberId());
- record.setSymbol(order.getSymbol());
- record.setPrice(profitLossPrice.add(order.getPrePaymentAmount()));
- memberAccountFlowEntityDao.insert(record);
- }
-
-
- /**
- * 限价委托
- *
- * @param
- */
- public void dealLimitBuyOrder(List<ContractEntrustOrderEntity> orderList) {
- //List<CoinsCoinsOrder> orderList = orderMapper.selectOrderByBatchNo(batchno);
- if (CollectionUtils.isNotEmpty(orderList)) {
- ContractHoldOrderEntity contractHoldOrderEntity = null;
- for (ContractEntrustOrderEntity coinsCoinsOrder : orderList) {
- MemberWalletContractEntity wallet = memberWalletContractService.findWalletContractByMemberIdAndSymbol(coinsCoinsOrder.getMemberId(), "USDT");
- if (wallet == null) {
- continue;
- }
-
- // 委托单bean转换为持仓单bean
- contractHoldOrderEntity = ContractEntrustOrderEntityMapper.INSTANCE.entrustOrderToHoldOrder(coinsCoinsOrder);
- contractHoldOrderEntity.setId(null);
- Long memId = coinsCoinsOrder.getMemberId();
- MemberEntity memberEntity = memberService.getById(memId);
- BigDecimal entrustPrice = coinsCoinsOrder.getEntrustPrice();
- int symbolCnt = coinsCoinsOrder.getSymbolCnt();
- int type = coinsCoinsOrder.getEntrustType();
-
- if (type == 1) {
- // 开多
- contractHoldOrderEntity.setOpeningType(ContractHoldOrderEntity.OPENING_TYPE_MORE);
- } else {
- // 开空
- contractHoldOrderEntity.setOpeningType(ContractHoldOrderEntity.OPENING_TYPE_LESS);
- }
-
- //持仓单赋值
- contractHoldOrderEntity.setMemberId(memId);
- contractHoldOrderEntity.setIsCanClosing(ContractHoldOrderEntity.ORDER_CAN_CLOSING_Y);
- contractHoldOrderEntity.setMarkPrice(coinsCoinsOrder.getEntrustPrice());
- contractHoldOrderEntity.setBondAmount(coinsCoinsOrder.getBondAmount());
- // 开仓手续费 建仓价*规格*手数*手续费率
- BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(coinsCoinsOrder.getSymbol());
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
- BigDecimal openFeePrice = coinsCoinsOrder.getEntrustPrice().multiply(lotNumber)
- .multiply(new BigDecimal(coinsCoinsOrder.getSymbolCnt()))
- .multiply(tradeSettingEntity.getFeeRatio().divide(new BigDecimal(100)))
- .setScale(8, BigDecimal.ROUND_DOWN);
- contractHoldOrderEntity.setOpeningFeeAmount(openFeePrice);
- contractHoldOrderEntity.setVersion(1);
- BigDecimal forceSetPrice = CalculateUtil.getForceSetPrice(coinsCoinsOrder.getBondAmount().subtract(openFeePrice), entrustPrice, symbolCnt, lotNumber, type, memberEntity);
-
- contractHoldOrderEntity.setForceClosingPrice(forceSetPrice);
- contractHoldOrderEntity.setLeverRatio(coinsCoinsOrder.getLeverRatio());
- contractHoldOrderEntity.setOpeningPrice(entrustPrice);
- contractHoldOrderEntity.setTradeType(ContractHoldOrderEntity.TRADE_TYPE_LIMIT);
- contractHoldOrderEntity.setOperateNo(1);
- contractHoldOrderService.save(contractHoldOrderEntity);
-
- // 需要一个历史插入
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(contractHoldOrderEntity);
- contractOrderEntity.setEntrustOpeningPrice(coinsCoinsOrder.getEntrustPrice());
- contractOrderEntity.setEntrustTime(coinsCoinsOrder.getCreateTime());
- contractOrderEntity.setOpeningTime(new Date());
-
- contractOrderEntity.setId(null);
- contractOrderService.save(contractOrderEntity);
- // 发送爆仓的队列
- // 市价
- if (coinsCoinsOrder.getEntrustType() == 1) {
- // 开多
- OrderModel model = new OrderModel(contractHoldOrderEntity.getId(), 6, contractHoldOrderEntity.getForceClosingPrice().setScale(8, RoundingMode.HALF_UP).toPlainString(), coinsCoinsOrder.getSymbol(), 1);
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- } else {
- // 开空
- OrderModel model = new OrderModel(contractHoldOrderEntity.getId(), 7, contractHoldOrderEntity.getForceClosingPrice().setScale(8, RoundingMode.HALF_UP).toPlainString(), coinsCoinsOrder.getSymbol(), 1);
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- // 扣除手续费
- BigDecimal totalBalance = openFeePrice.negate();
- contractEntrustOrderService.removeById(coinsCoinsOrder.getId());
- memberWalletContractService.increaseWalletContractBalanceById(null, totalBalance, coinsCoinsOrder.getBondAmount().negate(), wallet.getId());
-
- //返佣
- ThreadPoolUtils.calReturnMoney(memberEntity.getId(), openFeePrice, contractOrderEntity, AgentReturnEntity.ORDER_TYPE_OPEN);
- }
- }
- }
-
- /**
- * 爆仓
- *
- * @param
- */
- public void dealCoinOut(List<ContractHoldOrderEntity> orderList, List<OrderModel> orderModels) {
- if (CollectionUtils.isNotEmpty(orderList)) {
- Map<Long, Integer> modelMap = new HashMap<Long, Integer>();
- for (OrderModel model : orderModels) {
- modelMap.put(model.getOrderId(), model.getOperateNo());
- }
- for (ContractHoldOrderEntity coinsOrder : orderList) {
- Long orderId = coinsOrder.getId();
- Integer operateNo = coinsOrder.getOperateNo();
- //判断当前订单是否是最新的爆仓价 不相等时直接进入下一个订单
- if (!modelMap.get(orderId).equals(operateNo)) {
- // 将订单更新为可平仓并删除批次号
- contractHoldOrderService.updateOrderIsCanClosingAndBatchNoById(orderId);
- continue;
- }
- boolean isDone = false;
- Long memId = coinsOrder.getMemberId();
- BigDecimal nowPrice = coinsOrder.getForceClosingPrice();
- // 创建订单(加入历史表的订单)
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(coinsOrder);
-
- //查询是否满足爆仓条件
- if (coinsOrder.getOpeningType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
- //如果是开多,当前价小于预估强平价即为爆仓
- // 设置平仓类型 // 爆仓平多
- contractOrderEntity.setClosingType(4);
- //更新用户钱包数据
- isDone = true;
- } else {
- //如果是开空,当前价大于预估强平价即为爆仓
- contractOrderEntity.setClosingType(5);
- //更新主表订单状态位为“已平仓”
- isDone = true;
-
- }
- if (isDone) {
- //删除次仓订单
- contractHoldOrderService.removeById(orderId);
- // 订单状态转换
- if (ContractOrderEntity.ORDER_TYPE_OPEN_MORE == contractOrderEntity.getOrderType()) {
- contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_MORE);
- } else {
- contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_LESS);
- }
- //更新主表订单状态位为“已平仓”
- contractOrderEntity.setId(null);
- contractOrderEntity.setClosingPrice(nowPrice);
- contractOrderEntity.setClosingTime(new Date());
- contractOrderEntity.setClosingFeeAmount(coinsOrder.getOpeningFeeAmount());
- contractOrderEntity.setRewardAmount(coinsOrder.getBondAmount().subtract(contractOrderEntity.getOpeningFeeAmount()).negate());
- contractOrderService.save(contractOrderEntity);
-
- //更新用户钱包数据
- MemberWalletContractEntity usdt = memberWalletContractService.findWalletContractByMemberIdAndSymbol(memId, "USDT");
-
- // 减去的时候用负数
- BigDecimal totalPrice = coinsOrder.getBondAmount().negate();
- memberWalletContractService.increaseWalletContractBalanceById(null, totalPrice, null, usdt.getId());
- // 流水记录 TODO
- MemberAccountFlowEntity record = new MemberAccountFlowEntity();
- record.setCreateTime(new Date());
- record.setSource("系统自动平仓");
- record.setRemark("系统自动平仓");
- record.setBalance(usdt.getAvailableBalance());
- record.setMemberId(memId);
- record.setSymbol(coinsOrder.getSymbol());
- record.setPrice(coinsOrder.getBondAmount());
- memberAccountFlowEntityDao.insert(record);
- }
- }
- }
- }
-
- public void calYj(Long mid, BigDecimal money, ContractOrderEntity order, int type) {
- PlatformTradeSettingEntity tradeSetting = cacheSettingUtils.getTradeSetting();
- if (money != null) {
- money = money.multiply(tradeSetting.getFeeSpreadRatio());
- }
- MemberEntity member = memberService.getById(mid);
- String[] referenceIds = member.getRefererIds().split(",");
- List<String> ids = Arrays.asList(referenceIds);
-
- if (MemberEntity.ACCOUNT_TYPE_TEST.equals(member.getAccountType())) {
- return;
- }
-
- // 判断该用户是否为代理商
- NeedMoneyMemberVo needMoneyMember = memberService.selectFriendRelationUserByMemberId(mid);
-
- // 查询该用户下所有需要返佣的代理商
- List<NeedMoneyMemberVo> list = memberService.selectAllNeedMoneyMember(ids);
- TreeMap<Integer, NeedMoneyMemberVo> treeMap = new TreeMap<>(new Comparator<Integer>() {
- @Override
- public int compare(Integer o1, Integer o2) {
- return o2.compareTo(o1);
- }
- });
- // 建立层级关系
- for (int i = 0; i < list.size(); i++) {
- treeMap.put(list.get(i).getLevelId(), list.get(i));
- }
-
- // 该用户为代理商则判断is_self字段,判断是否保留其手续费
- // 该用户为代理商则判断is_self字段,判断是否保留其手续费
- if (needMoneyMember != null && needMoneyMember.getFeeIsSelf() == 1) {
- treeMap.put(needMoneyMember.getLevelId(), needMoneyMember);
- }
-
-
- // 存放uid以及对应uid用户的佣金
- Map<String, Map<String, BigDecimal>> map = new HashMap<>();
- Iterator<Map.Entry<Integer, NeedMoneyMemberVo>> it = treeMap.entrySet().iterator();
- BigDecimal lastRate = BigDecimal.ZERO;
- BigDecimal lastYj = BigDecimal.ZERO;
- while (it.hasNext()) {
- Map.Entry<Integer, NeedMoneyMemberVo> entry = it.next();
- NeedMoneyMemberVo member1 = entry.getValue();
- Map<String, BigDecimal> returnValue = new HashMap<>();
- returnValue.put("ratio", member1.getReturnRatio());
- returnValue.put("lastRate", lastRate);
- // 上下级佣金比率相减后乘以手续费 -- 即用户所得佣金
- lastYj = (member1.getReturnRatio().subtract(lastRate)).multiply(money);
- lastRate = member1.getReturnRatio();
- returnValue.put("returnMoney", lastYj);
- map.put(member1.getInviteId(), returnValue);
- }
-
- // 输出对应佣金是否正确
- Iterator<Map.Entry<String, Map<String, BigDecimal>>> it1 = map.entrySet().iterator();
- List<AgentReturnEntity> agentList = new ArrayList<AgentReturnEntity>();
- while (it1.hasNext()) {
- Map.Entry<String, Map<String, BigDecimal>> entry = it1.next();
- // System.out.println(entry.getKey() + "-----" + entry.getValue());
- MemberEntity agentMember = memberService.selectMemberInfoByInviteId(entry.getKey());
- AgentReturnEntity agent = new AgentReturnEntity();
- agent.setMemberId(mid);
- agent.setOrderId(order.getId());
- agent.setOrderNo(order.getOrderNo());
- agent.setRefererId(agentMember.getId());
- agent.setOrderType(order.getOrderType());
- agent.setReturnSymbol(order.getSymbol());
- agent.setIsReturn(0);
- agent.setReturnAmount(entry.getValue().get("returnMoney"));
- agent.setChildReturnRatio(entry.getValue().get("lastRate"));
- agent.setReturnRatio(entry.getValue().get("ratio"));
- agent.setClosingType(order.getClosingType());
- if (type == 1) {//开仓
- agent.setOpeningFeeAmount(order.getOpeningFeeAmount());
- } else if (type == 2) {//平仓
- agent.setClosingFeeAmount(order.getClosingFeeAmount());
- } else {//持仓费
- agent.setHoldingFeeAmount(order.getHoldAmount());
- }
- agent.setInviteId(entry.getKey());
- agentReturnDao.insert(agent);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/impl/RabbitOrderServiceImpl.java b/src/main/java/com/xcong/excoin/modules/contract/service/impl/RabbitOrderServiceImpl.java
deleted file mode 100644
index 1f4e3ed..0000000
--- a/src/main/java/com/xcong/excoin/modules/contract/service/impl/RabbitOrderServiceImpl.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.xcong.excoin.modules.contract.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.common.enumerates.OrderClosingTypeEnum;
-import com.xcong.excoin.common.system.service.CommonService;
-import com.xcong.excoin.modules.contract.dao.ContractHoldOrderDao;
-import com.xcong.excoin.modules.contract.dao.ContractOrderDao;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.mapper.ContractHoldOrderEntityMapper;
-import com.xcong.excoin.modules.contract.service.RabbitOrderService;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.dao.MemberSettingDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
-import com.xcong.excoin.modules.member.entity.AgentReturnEntity;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberSettingEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import com.xcong.excoin.utils.*;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.util.Date;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-06-01
- **/
-@Slf4j
-@Service
-public class RabbitOrderServiceImpl implements RabbitOrderService {
-
- @Resource
- private MemberDao memberDao;
-
- @Resource
- private OrderWebsocketServiceImpl orderWebsocketService;
-
- @Resource
- private ContractHoldOrderDao contractHoldOrderDao;
-
- @Resource
- private ContractOrderDao contractOrderDao;
-
- @Resource
- private CommonService commonService;
-
- @Resource
- private MemberWalletContractDao memberWalletContractDao;
-
- @Resource
- private CacheSettingUtils cacheSettingUtils;
-
- @Resource
- private RedisUtils redisUtils;
- @Resource
- private MemberSettingDao memberSettingDao;
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void cancelHoldOrder(List<Long> ids) {
- if (CollUtil.isNotEmpty(ids)) {
- if (ids.size() == 1) {
- ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectById(ids.get(0));
- cancelHoldOrderMethod(holdOrderEntity);
- } else {
- List<ContractHoldOrderEntity> holdOrderEntities = contractHoldOrderDao.selectBatchIds(ids);
- if (CollUtil.isNotEmpty(holdOrderEntities)) {
- for (ContractHoldOrderEntity holdOrder : holdOrderEntities) {
- cancelHoldOrderMethod(holdOrder);
- }
- }
- }
- }
- }
-
- public void cancelHoldOrderMethod(ContractHoldOrderEntity holdOrderEntity) {
- String symbol = holdOrderEntity.getSymbol();
- // 获取最新价
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol)));
-
- MemberEntity memberEntity = memberDao.selectById(holdOrderEntity.getMemberId());
-
- MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(holdOrderEntity.getMemberId(), CoinTypeEnum.USDT.name());
- if (walletContract != null) {
- // 删除持仓表订单
- contractHoldOrderDao.deleteById(holdOrderEntity.getId());
-
- BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(symbol);
- // 盈亏
- BigDecimal profitOrLoss = BigDecimal.ZERO;
- Integer orderType = null;
- Integer closingType = null;
-
- MemberSettingEntity memberSettingEntity = memberSettingDao.selectMemberSettingByMemberId(memberEntity.getId());
- // 开多
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
- newPrice = newPrice.multiply(BigDecimal.ONE.subtract(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN)));
- // (最新价-开仓价)*规格*张数
- profitOrLoss = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
- orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_MORE;
- closingType = OrderClosingTypeEnum.CLOSE_MORE.getValue();
- // 开空
- } else {
- newPrice = newPrice.multiply(BigDecimal.ONE.add(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN)));
- // (开仓价-最新价)*规格*张数
- profitOrLoss = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
- orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_LESS;
- closingType = OrderClosingTypeEnum.CLOSE_LESS.getValue();
- }
-
- if (memberEntity.getIsProfit() == MemberEntity.IS_PROFIT_Y) {
- PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
- if (profitOrLoss.compareTo(BigDecimal.ZERO) > -1) {
- profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.subtract(tradeSettingEntity.getProfitParam()));
- } else {
- profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.add(tradeSettingEntity.getProfitParam()));
- }
- }
-
- // 盈亏比例(回报率)
- BigDecimal rewardRatio = profitOrLoss.divide(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), 8, BigDecimal.ROUND_DOWN);
-
- ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity);
- contractOrderEntity.setId(null);
- contractOrderEntity.setOrderType(orderType);
- contractOrderEntity.setClosingPrice(newPrice);
- contractOrderEntity.setClosingFeeAmount(holdOrderEntity.getOpeningFeeAmount());
- contractOrderEntity.setClosingTime(new Date());
- contractOrderEntity.setClosingType(closingType);
- contractOrderEntity.setRewardAmount(profitOrLoss);
- contractOrderEntity.setRewardRatio(rewardRatio);
- contractOrderDao.insert(contractOrderEntity);
-
- // 计算盈利或亏损后可用金额和总金额应该增加或减少的
- BigDecimal addMoney = holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()).add(profitOrLoss);
- memberWalletContractDao.increaseWalletContractBalanceById(addMoney, profitOrLoss.subtract(contractOrderEntity.getOpeningFeeAmount()), null, walletContract.getId());
-
- // 流水
- LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), addMoney, walletContract.getAvailableBalance().add(addMoney), holdOrderEntity.getSymbol(), "平仓", "平仓");
-
- // 计算佣金
- ThreadPoolUtils.calReturnMoney(memberEntity.getId(), contractOrderEntity.getClosingFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE);
- }
-
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/Example.java b/src/main/java/com/xcong/excoin/modules/gateApi/Example.java
deleted file mode 100644
index c8f8ff3..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/Example.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-// Import classes:
-import io.gate.gateapi.ApiClient;
-import io.gate.gateapi.ApiException;
-import io.gate.gateapi.Configuration;
-import io.gate.gateapi.GateApiException;
-import io.gate.gateapi.api.FuturesApi;
-import io.gate.gateapi.auth.*;
-import io.gate.gateapi.models.*;
-import io.gate.gateapi.api.AccountApi;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-
-
-/**
- * Gate SDK API 使用示例。
- *
- * <h3>演示内容</h3>
- * <ol>
- * <li>通过 API Key/Secret 初始化客户端</li>
- * <li>查询期货账户余额</li>
- * <li>设置双向持仓模式</li>
- * <li>设置杠杆倍数</li>
- * <li>切换保证金模式(全仓/逐仓)</li>
- * </ol>
- *
- * <h3>注意</h3>
- * 此文件仅作为 SDK 用法参考,不影响实际策略运行。
- * 当前策略中相同功能的实现在 {@code GateGridTradeService.init()} 中。
- *
- * @author Administrator
- */
-@Slf4j
-public class Example {
- /**
- * 示例入口:依次执行查询账户 → 设置双向持仓 → 设杠杆 → 切换保证金模式。
- */
- public static void main(String[] args) {
- ApiClient defaultClient = Configuration.getDefaultApiClient();
- defaultClient.setBasePath("https://api-testnet.gateapi.io/api/v4");
-// defaultClient.setBasePath("https://api.gateio.ws/api/v4");
-
- // Configure APIv4 authorization: apiv4
- defaultClient.setApiKeySecret("d90ca272391992b8e74f8f92cedb21ec", "1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274");
-
- try {
-
- String CONTRACT = "ETH_USDT";
- String SETTLE = "usdt";
- //保证金模式 isolated/cross
- String MARGINMODE = "CROSS";
- String LEVERAGE = "100";
- FuturesApi futuresApi = new FuturesApi(defaultClient);
- FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
- log.info("[Gate] 初始本金: {} USDT", account.getTotal());
-
- //设置持仓模式为双向持仓
- Boolean inDualMode = account.getInDualMode();
- if (!inDualMode) {
- try {
- futuresApi.setDualModeCall(SETTLE,true,null).execute();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- try {
- futuresApi.updateDualModePositionLeverageCall(
- SETTLE, CONTRACT, LEVERAGE,
- null, null).execute();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- if (!MARGINMODE.equals(account.getMarginMode())) {
-
- UpdateDualCompPositionCrossModeRequest updateDualCompPositionCrossModeRequest = new UpdateDualCompPositionCrossModeRequest();
- updateDualCompPositionCrossModeRequest.setMode(MARGINMODE);
- updateDualCompPositionCrossModeRequest.setContract(CONTRACT);
- try {
- futuresApi.updateDualCompPositionCrossModeCall(SETTLE, updateDualCompPositionCrossModeRequest, null).execute();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- } catch (GateApiException e) {
- System.err.println(String.format("Gate api exception, label: %s, message: %s", e.getErrorLabel(), e.getMessage()));
- e.printStackTrace();
- } catch (ApiException e) {
- System.err.println("Exception when calling AccountApi#getAccountDetail");
- e.printStackTrace();
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
deleted file mode 100644
index 9b207cc..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
+++ /dev/null
@@ -1,346 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Gate 交易模块全局配置,策略的唯一参数入口。
- *
- * <h3>定位</h3>
- * 通过 Builder 模式将所有运行参数集中管理,避免策略参数散落在多个类中。
- * 运行时动态参数(step、gridElements、baseLongTraderParam、baseShortTraderParam)
- * 由 {@link GateGridTradeService} 在策略执行过程中写入。
- *
- * <h3>参数分类</h3>
- * <table>
- * <tr><th>类别</th><th>参数</th><th>用途</th></tr>
- * <tr><td>认证</td><td>apiKey, apiSecret</td><td>REST/WS 签名认证</td></tr>
- * <tr><td>交易标的</td><td>contract, leverage, quantity, contractMultiplier</td><td>合约、杠杆、张数、乘数</td></tr>
- * <tr><td>持仓</td><td>marginMode, positionMode</td><td>全仓/逐仓、单向/双向</td></tr>
- * <tr><td>网格策略</td><td>gridRate, gridQueueSize, priceScale</td><td>间距比例、队列容量、价格精度(交易所tick)</td></tr>
- * <tr><td>止盈止损</td><td>overallTp, maxLoss</td><td>整体止盈/亏损阈值(USDT),触发后策略停止</td></tr>
- * <tr><td>风控</td><td>marginRatioLimit, reopenMaxRetries</td><td>保证金占比上限、补仓重试次数</td></tr>
- * <tr><td>盈亏计算</td><td>contractMultiplier, unrealizedPnlPriceMode</td><td>合约乘数、未实现盈亏计价模式</td></tr>
- * <tr><td>运行时</td><td>step, gridElements, baseLongTraderParam, baseShortTraderParam</td><td>由策略动态填充</td></tr>
- * </table>
- *
- * <h3>priceScale 说明</h3>
- * 价格精度表示交易所允许的最小价格单位的小数位数:
- * <ul>
- * <li>XAU_USDT: tick=0.1 → priceScale=1</li>
- * <li>ETH_USDT: tick=0.01 → priceScale=2</li>
- * </ul>
- * 所有价格计算必须对齐到 tick 整数倍,否则 Gate API 返回
- * {@code invalid argument: trigger.price price is not an integer multiple of a price unit}。
- *
- * <h3>gridElements 生命周期</h3>
- * <ol>
- * <li>项目启动时初始化为空 ArrayList</li>
- * <li>{@code tryGenerateQueues()} 中通过 {@code updateGridElements()} 填充,同时触发
- * {@link GridElement#rebuildIndex(List)} 建立全局 O(1) 索引</li>
- * <li>每次挂单/止盈操作后通过 {@link GridElement#refreshIndices()} 更新索引</li>
- * </ol>
- *
- * @author Administrator
- */
-public class GateConfig {
-
- /**
- * 未实现盈亏(unrealizedPnl)计价模式。
- *
- * <ul>
- * <li>{@link #LAST_PRICE} — 按最新成交价计算,变动快、更贴近实际平仓价</li>
- * <li>{@link #MARK_PRICE} — 按标记价格计算,变动平稳、过滤市场噪音</li>
- * </ul>
- */
- public enum PnLPriceMode {
- /** 按最新成交价计算未实现盈亏 */
- LAST_PRICE,
- /** 按标记价格计算未实现盈亏,需通过 {@link GateGridTradeService#setMarkPrice(BigDecimal)} 注入 */
- MARK_PRICE
- }
-
- /** Gate API v4 密钥 */
- private final String apiKey;
- /** Gate API v4 签名密钥 */
- private final String apiSecret;
- /** 合约名称(如 XAU_USDT) */
- private final String contract;
- /** 杠杆倍数 */
- private final String leverage;
- /** 保证金模式(cross / isolated) */
- private final String marginMode;
- /** 持仓模式(single / dual / dual_plus) */
- private final String positionMode;
- /** 网格间距比例(如 0.0035 表示 0.35%) */
- private final BigDecimal gridRate;
- /** 整体止盈阈值(USDT) */
- private final BigDecimal overallTp;
- /** 最大亏损阈值(USDT) */
- private final BigDecimal maxLoss;
- /** 下单数量(合约张数) */
- private final String quantity;
- /** 基底开仓张数(初始化时多空各开的张数,如 "10") */
- private final String baseQuantity;
- /** 预期收益(USDT),unrealisedPnl + available > 初始本金 + 此值时重置 */
- private final BigDecimal expectedProfit;
- /** 是否为生产环境 */
- private final boolean isProduction;
- /** 补仓最大重试次数 */
- private final int reopenMaxRetries;
- /** 网格队列容量 */
- private final int gridQueueSize;
- /** 保证金占初始本金比例上限 */
- private final BigDecimal marginRatioLimit;
- /** 合约乘数(单张合约代表的基础资产数量,如 BTC_USDT=0.001, ETH_USDT=0.01) */
- private final BigDecimal contractMultiplier;
- /** 价格精度(交易所价格的最小小数位数,如 XAU_USDT=1 表示 0.1 精度,ETH_USDT=2 表示 0.01 精度) */
- private final int priceScale;
- /** 未实现盈亏计价模式:最新价 / 标记价格 */
- private final PnLPriceMode unrealizedPnlPriceMode;
- /** 网格绝对步长(shortBaseEntryPrice × gridRate),运行时由队列生成逻辑设置 */
- private BigDecimal step;
- /** 网格元素列表,由队列初始化时同步填充,包含完整的多空仓挂单状态 */
- private volatile List<GridElement> gridElements = new ArrayList<>();
- /** 基座多头挂单参数,在基座成交后由 tryGenerateQueues 填充 */
- private TraderParam baseLongTraderParam;
- /** 基座空头挂单参数,在基座成交后由 tryGenerateQueues 填充 */
- private TraderParam baseShortTraderParam;
-
- private GateConfig(Builder builder) {
- this.apiKey = builder.apiKey;
- this.apiSecret = builder.apiSecret;
- this.contract = builder.contract;
- this.leverage = builder.leverage;
- this.marginMode = builder.marginMode;
- this.positionMode = builder.positionMode;
- this.gridRate = builder.gridRate;
- this.overallTp = builder.overallTp;
- this.maxLoss = builder.maxLoss;
- this.quantity = builder.quantity;
- this.baseQuantity = builder.baseQuantity;
- this.expectedProfit = builder.expectedProfit;
- this.isProduction = builder.isProduction;
- this.reopenMaxRetries = builder.reopenMaxRetries;
- this.gridQueueSize = builder.gridQueueSize;
- this.marginRatioLimit = builder.marginRatioLimit;
- this.contractMultiplier = builder.contractMultiplier;
- this.priceScale = builder.priceScale;
- this.unrealizedPnlPriceMode = builder.unrealizedPnlPriceMode;
- }
-
- // ==================== REST/WS 地址 ====================
-
- /**
- * 根据环境返回 REST API 基础路径。
- * <ul>
- * <li>测试网: {@code https://api-testnet.gateapi.io/api/v4}</li>
- * <li>生产网: {@code https://api.gateio.ws/api/v4}</li>
- * </ul>
- */
- public String getRestBasePath() {
- return isProduction
- ? "https://api.gateio.ws/api/v4"
- : "https://api-testnet.gateapi.io/api/v4";
- }
-
- /**
- * 根据环境返回 WebSocket 地址。
- * <ul>
- * <li>测试网: {@code wss://ws-testnet.gate.com/v4/ws/futures/usdt}</li>
- * <li>生产网: {@code wss://fx-ws.gateio.ws/v4/ws/usdt}</li>
- * </ul>
- */
- public String getWsUrl() {
- return isProduction
- ? "wss://fx-ws.gateio.ws/v4/ws/usdt"
- : "wss://ws-testnet.gate.com/v4/ws/futures/usdt";
- }
-
- // ==================== 认证信息 ====================
-
- /** @return Gate API v4 密钥 */
- public String getApiKey() { return apiKey; }
- /** @return Gate API v4 签名密钥,用于 HMAC-SHA512 签名 */
- public String getApiSecret() { return apiSecret; }
-
- // ==================== 交易标的 ====================
-
- /** @return 合约名称(如 ETH_USDT、XAU_USDT) */
- public String getContract() { return contract; }
- /** @return 杠杆倍数(如 "100" 表示 100x) */
- public String getLeverage() { return leverage; }
-
- // ==================== 持仓配置 ====================
-
- /** @return 保证金模式(cross=全仓 / isolated=逐仓) */
- public String getMarginMode() { return marginMode; }
- /** @return 持仓模式(single=单向 / dual=双向 / dual_plus) */
- public String getPositionMode() { return positionMode; }
-
- // ==================== 策略参数 ====================
-
- /** @return 网格间距比例(如 0.0015 表示 0.15%),用于生成价格队列和计算止盈价 */
- public BigDecimal getGridRate() { return gridRate; }
- /** @return 整体止盈阈值(USDT),累计已实现盈亏 ≥ 此值时策略停止 */
- public BigDecimal getOverallTp() { return overallTp; }
- /** @return 最大亏损阈值(USDT),累计已实现盈亏 ≤ -此值时策略停止 */
- public BigDecimal getMaxLoss() { return maxLoss; }
- /** @return 每次下单的张数(如 "1" 表示 1 张合约) */
- public String getQuantity() { return quantity; }
- /** @return 基底开仓张数(初始化时多空各开的张数,如 "10") */
- public String getBaseQuantity() { return baseQuantity; }
- /** @return 预期收益(USDT),unrealisedPnl + available > 初始本金 + 此值时重置 */
- public BigDecimal getExpectedProfit() { return expectedProfit; }
- /** @return 网格价格队列的容量上限(超出时截断尾部) */
- public int getGridQueueSize() { return gridQueueSize; }
-
- // ==================== 风险控制 ====================
-
- /** @return 保证金占初始本金比例上限(默认 0.2 即 20%),超限跳过开仓 */
- public BigDecimal getMarginRatioLimit() { return marginRatioLimit; }
- /** @return 补仓最大重试次数(当前版本未使用) */
- public int getReopenMaxRetries() { return reopenMaxRetries; }
-
- // ==================== 盈亏计算 ====================
-
- /** @return 合约乘数(单张合约代表的基础资产数量,如 ETH_USDT=0.01) */
- public BigDecimal getContractMultiplier() { return contractMultiplier; }
- /** @return 价格精度(交易所价格的小数位数,如 1=0.1精度,2=0.01精度),用于价格四舍五入 */
- public int getPriceScale() { return priceScale; }
- /** @return 未实现盈亏计价模式:LAST_PRICE(最新成交价)/ MARK_PRICE(标记价格) */
- public PnLPriceMode getUnrealizedPnlPriceMode() { return unrealizedPnlPriceMode; }
-
- // ==================== 运行时参数 ====================
-
- /** @return 网格绝对步长(shortBaseEntryPrice × gridRate),运行时设置 */
- public BigDecimal getStep() { return step; }
- /** 设置网格绝对步长(由 generateShortQueue 在运行时计算并注入) */
- public void setStep(BigDecimal step) { this.step = step; }
-
- // ==================== 网格元素列表 ====================
-
- /** @return 网格元素列表(队列初始化后填充),线程不安全,仅由策略线程单线程写入 */
- public List<GridElement> getGridElements() { return gridElements; }
- /** 设置网格元素列表(由队列生成逻辑写入),同时重建全局 ID 索引 */
- public void setGridElements(List<GridElement> gridElements) {
- this.gridElements = gridElements;
- GridElement.rebuildIndex(gridElements);
- }
-
- // ==================== 基座挂单参数 ====================
-
- /** @return 基座多头挂单参数 */
- public TraderParam getBaseLongTraderParam() { return baseLongTraderParam; }
- /** 设置基座多头挂单参数(由 tryGenerateQueues 在基座成交后填充) */
- public void setBaseLongTraderParam(TraderParam baseLongTraderParam) { this.baseLongTraderParam = baseLongTraderParam; }
-
- /** @return 基座空头挂单参数 */
- public TraderParam getBaseShortTraderParam() { return baseShortTraderParam; }
- /** 设置基座空头挂单参数(由 tryGenerateQueues 在基座成交后填充) */
- public void setBaseShortTraderParam(TraderParam baseShortTraderParam) { this.baseShortTraderParam = baseShortTraderParam; }
-
- // ==================== 环境 ====================
-
- /** @return 是否为生产环境(true=实盘生产网 / false=模拟盘测试网) */
- public boolean isProduction() { return isProduction; }
-
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * GateConfig 的流式构造器,提供合理的默认值。
- *
- * <h3>必填项</h3>
- * {@code apiKey} 和 {@code apiSecret} 必须设置,其余参数均有默认值。
- *
- * <h3>默认值</h3>
- * BTC_USDT / 10x / cross(全仓) / dual(双向) / gridRate=0.35% /
- * overallTp=0.5 / maxLoss=7.5 / quantity=1 / isProduction=false
- */
- public static class Builder {
- /** Gate API v4 密钥(必填) */
- private String apiKey;
- /** Gate API v4 签名密钥(必填) */
- private String apiSecret;
- /** 合约名称,默认 BTC_USDT */
- private String contract = "BTC_USDT";
- /** 杠杆倍数,默认 "10" */
- private String leverage = "10";
- /** 保证金模式,默认 "cross"(全仓) */
- private String marginMode = "cross";
- /** 持仓模式,默认 "dual"(双向) */
- private String positionMode = "dual";
- /** 网格间距比例,默认 0.0035(0.35%) */
- private BigDecimal gridRate = new BigDecimal("0.0035");
- /** 整体止盈阈值(USDT),默认 0.5 */
- private BigDecimal overallTp = new BigDecimal("0.5");
- /** 最大亏损阈值(USDT),默认 7.5 */
- private BigDecimal maxLoss = new BigDecimal("7.5");
- /** 每次下单张数,默认 "1" */
- private String quantity = "1";
- /** 基底开仓张数,默认 "10"(初始化时多空各开10张) */
- private String baseQuantity = "10";
- /** 预期收益(USDT),默认 0.5 */
- private BigDecimal expectedProfit = new BigDecimal("0.5");
- /** 是否为生产环境,默认 false(测试网) */
- private boolean isProduction = false;
- /** 补仓最大重试次数,默认 3 */
- private int reopenMaxRetries = 3;
- /** 网格队列容量,默认 50 */
- private int gridQueueSize = 300;
- /** 保证金占初始本金比例上限,默认 0.2(20%) */
- private BigDecimal marginRatioLimit = new BigDecimal("0.2");
- /** 合约乘数,默认 0.001 */
- private BigDecimal contractMultiplier = new BigDecimal("0.001");
- /** 价格精度(交易所价格的小数位数),默认 1(0.1 精度) */
- private int priceScale = 1;
- /** 未实现盈亏计价模式,默认 LAST_PRICE(最新成交价) */
- private PnLPriceMode unrealizedPnlPriceMode = PnLPriceMode.LAST_PRICE;
-
- /** 设置 API Key */
- public Builder apiKey(String apiKey) { this.apiKey = apiKey; return this; }
- /** 设置 API Secret */
- public Builder apiSecret(String apiSecret) { this.apiSecret = apiSecret; return this; }
- /** 设置合约名称 */
- public Builder contract(String contract) { this.contract = contract; return this; }
- /** 设置杠杆倍数 */
- public Builder leverage(String leverage) { this.leverage = leverage; return this; }
- /** 设置保证金模式(cross=全仓 / isolated=逐仓) */
- public Builder marginMode(String marginMode) { this.marginMode = marginMode; return this; }
- /** 设置持仓模式(single=单向 / dual=双向) */
- public Builder positionMode(String positionMode) { this.positionMode = positionMode; return this; }
- /** 设置网格间距比例 */
- public Builder gridRate(BigDecimal gridRate) { this.gridRate = gridRate; return this; }
- /** 设置整体止盈阈值(USDT) */
- public Builder overallTp(BigDecimal overallTp) { this.overallTp = overallTp; return this; }
- /** 设置最大亏损阈值(USDT) */
- public Builder maxLoss(BigDecimal maxLoss) { this.maxLoss = maxLoss; return this; }
- /** 设置每次下单张数 */
- public Builder quantity(String quantity) { this.quantity = quantity; return this; }
- /** 设置基底开仓张数 */
- public Builder baseQuantity(String baseQuantity) { this.baseQuantity = baseQuantity; return this; }
- /** 设置预期收益(USDT) */
- public Builder expectedProfit(BigDecimal expectedProfit) { this.expectedProfit = expectedProfit; return this; }
- /** 设置环境(true=实盘生产网 / false=模拟盘测试网) */
- public Builder isProduction(boolean isProduction) { this.isProduction = isProduction; return this; }
- /** 设置补仓最大重试次数 */
- public Builder reopenMaxRetries(int reopenMaxRetries) { this.reopenMaxRetries = reopenMaxRetries; return this; }
- /** 设置合约乘数(单张合约代表的基础资产数量) */
- public Builder contractMultiplier(BigDecimal contractMultiplier) { this.contractMultiplier = contractMultiplier; return this; }
- /** 设置价格精度(交易所价格的小数位数,如 1=0.1精度,2=0.01精度) */
- public Builder priceScale(int priceScale) { this.priceScale = priceScale; return this; }
- /** 设置保证金占初始本金比例上限 */
- public Builder marginRatioLimit(BigDecimal marginRatioLimit) { this.marginRatioLimit = marginRatioLimit; return this; }
- /** 设置网格队列容量 */
- public Builder gridQueueSize(int gridQueueSize) { this.gridQueueSize = gridQueueSize; return this; }
- /** 设置未实现盈亏计价模式 */
- public Builder unrealizedPnlPriceMode(PnLPriceMode mode) { this.unrealizedPnlPriceMode = mode; return this; }
-
- public GateConfig build() {
- return new GateConfig(this);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
deleted file mode 100644
index 7f30933..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ /dev/null
@@ -1,1660 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.StrUtil;
-import com.xcong.excoin.utils.dingtalk.DingTalkUtils;
-import io.gate.gateapi.ApiClient;
-import io.gate.gateapi.ApiException;
-import io.gate.gateapi.GateApiException;
-import io.gate.gateapi.api.AccountApi;
-import io.gate.gateapi.api.FuturesApi;
-import io.gate.gateapi.models.*;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.CandlestickChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionClosesChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionsChannelHandler;
-
-/**
- * 网格交易策略引擎 — 多空对冲网格。
- *
- * <h3>策略原理</h3>
- * 以空仓基底入场价(shortBaseEntryPrice)为价格基准,向上/向下各生成一个价格网格队列。
- * 价格触发网格层级时挂条件单,成交后自动挂止盈单。每笔止盈盈利 = step - minTick。
- *
- * <h3>完整生命周期</h3>
- * <pre>
- * init() → startGrid() → WAITING_KLINE
- * ↓
- * onKline(首根K线) → OPENING → 异步市价双开基底(开多+开空)
- * ↓
- * onPositionUpdate() → 基底成交 → baseLongOpened && baseShortOpened
- * ↓
- * tryGenerateQueues()
- * ├── generateShortQueue() ← 空仓价格队列(降序,从 shortBaseEntryPrice-step 向下)
- * ├── generateLongQueue() ← 多仓价格队列(升序,从 shortBaseEntryPrice+step 向上)
- * ├── updateGridElements() ← 构建 GridElement 列表 + TraderParam + 全局索引
- * ├── 挂基座止盈单(ID=0 的 long/short takeProfit)
- * └── 挂初始条件单(up=-1 多单, down=1 空单)
- * ↓
- * state = ACTIVE(每根K线反复执行以下循环)
- * ↓
- * onKline() → processLongGrid() + processShortGrid()
- * ├── 匹配队列元素 → 队列补偿 → 保证金检查
- * ├── 首元素方向:挂条件开仓单 → 订单ID + GridElement状态同步
- * └── 反向守卫:在 downGrid 位置挂对向单(价格区间+trigger方向校验)
- * ↓
- * onOrderUpdate() ← futures.orders / futures.autoorders 推送
- * ├── 匹配止盈单ID → 清空止盈状态(已成交)
- * └── 匹配挂单ID → 挂止盈条件单 → 止盈ID + GridElement状态同步
- * ↓
- * onPositionClose() → cumulativePnl 累加
- * ├── ≥ overallTp → STOPPED
- * └── ≤ -maxLoss → STOPPED
- * </pre>
- *
- * <h3>仓位线动态调整</h3>
- * <pre>
- * onPositionUpdate() 中仓位均价变化后:
- * longEntryPrice ↑ → 取消 高于 longEntryPrice 的空仓挂单(避免逆势空单)
- * shortEntryPrice ↓ → 取消 低于 shortEntryPrice 的多仓挂单(避免逆势多单)
- * </pre>
- *
- * <h3>关键公式</h3>
- * <pre>
- * step = shortBaseEntryPrice × gridRate ← 网格绝对步长
- * minTick = 10^(-priceScale) ← 交易所最小价格单位
- * 多止盈 = gridPrice + (step - minTick) ← 多仓止盈价
- * 空止盈 = gridPrice - (step - minTick) ← 空仓止盈价
- * 单笔盈利 = (step - minTick) × contractMultiplier × quantity ← USDT
- * </pre>
- *
- * <h3>线程模型</h3>
- * 所有 WS 回调(onKline/onPositionUpdate/onOrderUpdate 等)在 WS 回调线程中串行执行。
- * 下单/撤单操作提交到 GateTradeExecutor 的单线程池异步执行,避免阻塞 WS 线程。
- * stopGrid() 会将 state 设为 STOPPED,后续所有 WS 回调直接返回不再处理。
- *
- * @author Administrator
- */
-@Slf4j
-public class GateGridTradeService {
-
- public enum StrategyState {
- WAITING_KLINE, OPENING, ACTIVE, STOPPED
- }
-
- /**
- * 止盈条件单 order_type:仓位计划止盈止损 — 平多仓(支持部分平仓,size<0)。
- * 注意:不能用 close-long-position(仅支持全平且双仓需 auto_size),
- * 必须用 plan-close-long-position 以支持指定张数部分平仓。
- */
- private static final String ORDER_TYPE_CLOSE_LONG = "plan-close-long-position";
- /**
- * 止盈条件单 order_type:仓位计划止盈止损 — 平空仓(支持部分平仓,size>0)。
- * 注意:不能用 close-short-position(仅支持全平且双仓需 auto_size),
- * 必须用 plan-close-short-position 以支持指定张数部分平仓。
- */
- private static final String ORDER_TYPE_CLOSE_SHORT = "plan-close-short-position";
-
- private final GateConfig config;
- private final GateTradeExecutor executor;
- private final FuturesApi futuresApi;
- private static final String SETTLE = "usdt";
-
- private volatile StrategyState state = StrategyState.WAITING_KLINE;
-
- /** 空仓价格队列,降序排列(大→小),容量 gridQueueSize */
- private final List<BigDecimal> shortPriceQueue = Collections.synchronizedList(new ArrayList<>());
- /** 多仓价格队列,升序排列(小→大),容量 gridQueueSize */
- private final List<BigDecimal> longPriceQueue = Collections.synchronizedList(new ArrayList<>());
-
- /** 当前多仓条件单映射:订单ID → 止盈价格,订单成交后通过订单订阅推送匹配止盈 */
- private final Map<String, BigDecimal> currentLongOrderIds = Collections.synchronizedMap(new LinkedHashMap<>());
- /** 当前空仓条件单映射:订单ID → 止盈价格,订单成交后通过订单订阅推送匹配止盈 */
- private final Map<String, BigDecimal> currentShortOrderIds = Collections.synchronizedMap(new LinkedHashMap<>());
-
- /** 基底空头入场价 */
- private BigDecimal shortBaseEntryPrice;
- /** 基底多头入场价(仅记录,当前未被业务逻辑消费,保留以备后续使用) */
- private BigDecimal longBaseEntryPrice;
- /** 基底多头是否已开 */
- private volatile boolean baseLongOpened = false;
- /** 基底空头是否已开 */
- private volatile boolean baseShortOpened = false;
-
- /** 空头是否活跃(有仓位) */
- private volatile boolean shortActive = false;
- /** 多头是否活跃(有仓位) */
- private volatile boolean longActive = false;
-
- private volatile BigDecimal lastKlinePrice;
- private volatile BigDecimal markPrice = BigDecimal.ZERO;
- private volatile BigDecimal cumulativePnl = BigDecimal.ZERO;
- private volatile BigDecimal unrealizedPnl = BigDecimal.ZERO;
- private volatile BigDecimal longEntryPrice = BigDecimal.ZERO;
- private volatile BigDecimal shortEntryPrice = BigDecimal.ZERO;
- private volatile BigDecimal longPositionSize = BigDecimal.ZERO;
- private volatile BigDecimal shortPositionSize = BigDecimal.ZERO;
- private Long userId;
- private volatile BigDecimal initialPrincipal = BigDecimal.ZERO;
-
- public GateGridTradeService(GateConfig config) {
- this.config = config;
- ApiClient apiClient = new ApiClient();
- apiClient.setBasePath(config.getRestBasePath());
- apiClient.setApiKeySecret(config.getApiKey(), config.getApiSecret());
- this.futuresApi = new FuturesApi(apiClient);
- this.executor = new GateTradeExecutor(apiClient, config.getContract());
- }
-
- // ---- 初始化 ----
-
- /**
- * 初始化策略环境。
- *
- * <h3>执行顺序</h3>
- * <ol>
- * <li>获取用户 ID(用于私有频道订阅 payload)</li>
- * <li>获取账户信息 → 记录初始本金</li>
- * <li>如需要,切换为双向持仓模式</li>
- * <li>如需要,调整持仓模式(single/dual)</li>
- * <li>清除旧的止盈止损条件单</li>
- * <li>平掉所有已有仓位</li>
- * <li>设置杠杆倍数</li>
- * </ol>
- */
- public void init() {
- try {
- ApiClient detailClient = new ApiClient();
- detailClient.setBasePath(config.getRestBasePath());
- detailClient.setApiKeySecret(config.getApiKey(), config.getApiSecret());
- AccountDetail detail = new AccountApi(detailClient).getAccountDetail();
- this.userId = detail.getUserId();
- log.info("[Gate] 用户ID: {}", userId);
-
- FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
- this.initialPrincipal = new BigDecimal(account.getTotal());
- log.info("[Gate] 初始本金: {} USDT", initialPrincipal);
-
- futuresApi.cancelPriceTriggeredOrderList(SETTLE, config.getContract());
- log.info("[Gate] 旧条件单已清除");
- closeExistingPositions();
-
- //设置持仓模式为双向持仓
- Boolean inDualMode = account.getInDualMode();
- if (!inDualMode) {
- try {
- futuresApi.setDualModeCall(SETTLE,true,null).execute();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- try {
- futuresApi.updateDualModePositionLeverageCall(
- SETTLE, config.getContract(), config.getLeverage(),
- null, null).execute();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- if (!config.getMarginMode().equals(account.getMarginMode())) {
-
- UpdateDualCompPositionCrossModeRequest updateDualCompPositionCrossModeRequest = new UpdateDualCompPositionCrossModeRequest();
- updateDualCompPositionCrossModeRequest.setMode(config.getMarginMode());
- updateDualCompPositionCrossModeRequest.setContract(config.getContract());
- try {
- futuresApi.updateDualCompPositionCrossModeCall(SETTLE, updateDualCompPositionCrossModeRequest, null).execute();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- log.info("[Gate] 持仓模式: {} 余额: {}", config.getPositionMode(), account.getAvailable());
- log.info("[Gate] 杠杆: {}x {}", config.getLeverage(), config.getMarginMode());
- } catch (GateApiException e) {
- log.error("[Gate] 初始化失败, label:{}, msg:{}", e.getErrorLabel(), e.getMessage());
- } catch (ApiException e) {
- log.error("[Gate] 初始化失败, code:{}", e.getCode());
- }
- }
-
- /**
- * 平掉当前合约的所有已有仓位。
- *
- * <h3>平仓策略</h3>
- * <ul>
- * <li>单向持仓:size=相反数,reduceOnly=true,市价 IOC 平仓</li>
- * <li>双向持仓:size=0,close=false,autoSize=LONG/SHORT,reduceOnly=true,市价 IOC 全平</li>
- * </ul>
- *
- * <h3>注意事项</h3>
- * 双向持仓模式下必须使用 autoSize 参数,不能直接传负数 size,
- * 否则 Gate API 会拒绝(双向模式下空头 size 为负是正常的持仓方向)。
- */
- private void closeExistingPositions() {
- try {
- List<Position> positions = futuresApi.listPositions(SETTLE).execute();
- if (positions == null || positions.isEmpty()) { log.info("[Gate] 无已有仓位"); return; }
- for (Position pos : positions) {
- if (!config.getContract().equals(pos.getContract())) {
- continue;
- }
- String sizeStr = pos.getSize();
- long size = Long.parseLong(sizeStr);
- if (size == 0) {
- continue;
- }
- String closeSize = size > 0 ? String.valueOf(-size) : String.valueOf(Math.abs(size));
- Position.ModeEnum mode = pos.getMode();
- FuturesOrder closeOrder = new FuturesOrder();
- closeOrder.setContract(config.getContract());
- closeOrder.setPrice("0");
- closeOrder.setTif(FuturesOrder.TifEnum.IOC);
- closeOrder.setReduceOnly(true);
- if (mode != null && mode.getValue() != null && mode.getValue().contains("dual")) {
- closeOrder.setSize("0");
- closeOrder.setClose(false);
- closeOrder.setAutoSize(size > 0 ? FuturesOrder.AutoSizeEnum.LONG : FuturesOrder.AutoSizeEnum.SHORT);
- } else {
- closeOrder.setSize(closeSize);
- }
- closeOrder.setText("t-grid-init-close");
- futuresApi.createFuturesOrder(SETTLE, closeOrder, null);
- log.info("[Gate] 平已有仓位, 方向:{}, size:{}, mode:{}", size > 0 ? "多" : "空", sizeStr, mode);
- }
- } catch (GateApiException e) {
- log.warn("[Gate] 平仓位失败, label:{}, msg:{}", e.getErrorLabel(), e.getMessage());
- } catch (Exception e) {
- log.warn("[Gate] 平仓位异常", e);
- }
- }
-
- // ---- 启动/停止 ----
-
- /**
- * 启动网格策略。重置所有状态变量和队列,进入 WAITING_KLINE 等待首根 K 线。
- * 仅当当前状态为 WAITING_KLINE 或 STOPPED 时才允许启动。
- */
- public void startGrid() {
- if (state != StrategyState.WAITING_KLINE && state != StrategyState.STOPPED) {
- log.warn("[Gate] 策略已在运行中, state:{}", state);
- return;
- }
- state = StrategyState.WAITING_KLINE;
- cumulativePnl = BigDecimal.ZERO;
- unrealizedPnl = BigDecimal.ZERO;
- markPrice = BigDecimal.ZERO;
- longEntryPrice = BigDecimal.ZERO;
- shortEntryPrice = BigDecimal.ZERO;
- longPositionSize = BigDecimal.ZERO;
- shortPositionSize = BigDecimal.ZERO;
- baseLongOpened = false;
- baseShortOpened = false;
- longActive = false;
- shortActive = false;
- shortPriceQueue.clear();
- longPriceQueue.clear();
- currentLongOrderIds.clear();
- currentShortOrderIds.clear();
- log.info("[Gate] 网格策略已启动");
- }
-
- /**
- * 停止网格策略。取消所有条件单 → 关闭交易线程池。
- * 状态设为 STOPPED,K 线回调将直接返回不再处理。
- */
- public void stopGrid() {
- state = StrategyState.STOPPED;
- executor.cancelAllPriceTriggeredOrders();
- executor.shutdown();
- log.info("[Gate] 策略已停止, 累计盈亏: {}", cumulativePnl);
- }
-
- // ---- K线回调 ----
-
- /**
- * K 线回调入口。由 {@link CandlestickChannelHandler} 在收到 WebSocket K 线推送时调用。
- *
- * <h3>处理流程</h3>
- * <ol>
- * <li>更新 lastKlinePrice → 计算 unrealizedPnl(浮动盈亏)</li>
- * <li>STOPPED → 直接返回(仅保留盈亏更新)</li>
- * <li>WAITING_KLINE → 切换为 OPENING → 异步提交基底双开(开多+开空)</li>
- * <li>OPENING → 等待仓位推送回调生成队列,此处返回</li>
- * <li>ACTIVE → 执行 processShortGrid + processLongGrid</li>
- * </ol>
- *
- * <h3>注意</h3>
- * 基底双开下单提交到 GateTradeExecutor 的独立线程池中异步执行,
- * 成交状态由 onPositionUpdate 回调驱动,不阻塞 WS 回调线程。
- *
- * @param closePrice K 线收盘价(即当前最新成交价)
- */
- public void onKline(BigDecimal closePrice) {
- lastKlinePrice = closePrice;
- updateUnrealizedPnl();
- if (state == StrategyState.STOPPED) {
- try {
- futuresApi.cancelPriceTriggeredOrderList(SETTLE, config.getContract());
- } catch (ApiException e) {
- e.printStackTrace();
- }
- closeExistingPositions();
-
- BigDecimal totalPnl = cumulativePnl.add(unrealizedPnl);
- log.info("[Gate] 已实现:{}, 未实现:{}, 合计:{}",
- cumulativePnl, unrealizedPnl, totalPnl);
-
- startGrid();
- return;
- }
-
- //初始化0位置的开仓,并且用空的开仓价格,作为价格基准来划分网格
- if (state == StrategyState.WAITING_KLINE) {
- state = StrategyState.OPENING;
- log.info("[Gate] 首根K线到达,开基底仓位 多空各{}张...", config.getBaseQuantity());
- executor.openLong(config.getBaseQuantity(), (orderId) -> {
- TraderParam baseLongTp = TraderParam.builder()
- .entryOrderId(orderId)
- .build();
- config.setBaseLongTraderParam(baseLongTp);
- }, null);
- executor.openShort(negate(config.getBaseQuantity()), (orderId) -> {
- TraderParam baseShortTp = TraderParam.builder()
- .entryOrderId(orderId)
- .build();
- config.setBaseShortTraderParam(baseShortTp);
- }, null);
-
- return;
- }
-
- if (state != StrategyState.ACTIVE) {
- return;
- }
- checkProfitAndReset();
- }
-
- // ---- 仓位推送回调 ----
-
- /**
- * 仓位推送回调。由 {@link PositionsChannelHandler} 在收到 WebSocket 仓位更新时调用。
- *
- * <h3>处理逻辑</h3>
- * <ul>
- * <li><b>有仓位 (size ≠ 0)</b>:
- * <ul>
- * <li>首次开仓(基底):标记 baseOpened=true,记录基底入场价,双基底都成交后生成网格队列</li>
- * <li>仓位净减少(size.abs() < 之前记录值):止盈平仓后 → 检查反向条件单条件 →
- * 满足时以 entryPrice ± step 为止盈价挂反向市价单(订单ID + 止盈价存入 Map)</li>
- * <li>仓位净增加或不变:仅更新 positionSize,止盈由 {@link #onOrderUpdate} 通过订单订阅匹配处理</li>
- * </ul>
- * </li>
- * <li><b>无仓位 (size = 0)</b>:清空活跃标记和持仓量</li>
- * <li><b>Map 截断</b>:currentLongOrderIds / currentShortOrderIds 超过 5 个时,
- * 从 LinkedHashMap 头部删除最旧条目,保留最新 5 个</li>
- * </ul>
- *
- * @param contract 合约名称
- * @param mode 持仓模式(DUAL_LONG / DUAL_SHORT)
- * @param size 持仓张数(多头为正、空头为负)
- * @param entryPrice 当前持仓加权均价(交易所计算)
- */
- public void onPositionUpdate(String contract, Position.ModeEnum mode, BigDecimal size,
- BigDecimal entryPrice) {
- if (state == StrategyState.STOPPED || state == StrategyState.WAITING_KLINE) {
- return;
- }
-
- boolean hasPosition = size.abs().compareTo(BigDecimal.ZERO) > 0;
-
- if (Position.ModeEnum.DUAL_LONG == mode) {
- if (hasPosition) {
- longActive = true;
- longEntryPrice = entryPrice;
- if (!baseLongOpened) {
- longPositionSize = size;
- longBaseEntryPrice = entryPrice;
- baseLongOpened = true;
- log.info("[Gate] 基底多成交价: {}", longBaseEntryPrice);
- tryGenerateQueues();
- }else {
- longPositionSize = size;
-// checkShortEntryOrderToCancel();
-// checkLongEntryOrderToCancel();
- }
- } else {
- if (longActive && state == StrategyState.ACTIVE) {
- log.info("[Gate] 多仓持仓归零,重置策略");
- handlePositionZeroAndReset("多仓");
- }
- longActive = false;
- longPositionSize = BigDecimal.ZERO;
- }
- } else if (Position.ModeEnum.DUAL_SHORT == mode) {
- if (hasPosition) {
- shortActive = true;
- shortEntryPrice = entryPrice;
- if (!baseShortOpened) {
- shortPositionSize = size.abs();
- shortBaseEntryPrice = entryPrice;
- baseShortOpened = true;
- log.info("[Gate] 基底空成交价: {}", shortBaseEntryPrice);
- tryGenerateQueues();
- }else {
- shortPositionSize = size.abs();
-// checkShortEntryOrderToCancel();
-// checkLongEntryOrderToCancel();
- }
- } else {
- if (shortActive && state == StrategyState.ACTIVE) {
- log.info("[Gate] 空仓持仓归零,重置策略");
- handlePositionZeroAndReset("空仓");
- }
- shortActive = false;
- shortPositionSize = BigDecimal.ZERO;
- }
- }
- }
-
- private void checkShortEntryOrderToCancel() {
- List<GridElement> allLongOrders = GridElement.findAllShortOrders(shortEntryPrice);
- if (CollUtil.isNotEmpty(allLongOrders)){
- GridElement keep = allLongOrders.stream()
- .min((a, b) -> a.getGridPrice().compareTo(b.getGridPrice()))
- .orElse(null);
- for (GridElement e : allLongOrders) {
- if (e == keep) {
- continue;
- }
- executor.cancelConditionalOrder(
- e.getShortOrderId(),
- orderId -> {
- shortEntryTraderIdParam(
- e,
- null,
- false
- );
- }
- );
- if (e.getShortTakeProfitOrderId() != null){
- executor.cancelConditionalOrder(
- e.getShortTakeProfitOrderId(),
- orderId -> {
- shortTakeProfitTraderIdParam(
- e,
- null,
- false
- );
- }
- );
- }
- }
- }
- }
-
- private void checkLongEntryOrderToCancel() {
- List<GridElement> allShortOrders = GridElement.findAllLongOrders(longEntryPrice);
- if (CollUtil.isNotEmpty(allShortOrders)){
- GridElement keep = allShortOrders.stream()
- .max((a, b) -> a.getGridPrice().compareTo(b.getGridPrice()))
- .orElse(null);
- for (GridElement e : allShortOrders) {
- if (e == keep) {
- continue;
- }
- executor.cancelConditionalOrder(
- e.getLongOrderId(),
- orderId -> {
- longEntryTraderIdParam(
- e,
- null,
- false
- );
- }
- );
-
- if (e.getLongTakeProfitOrderId() != null){
- executor.cancelConditionalOrder(
- e.getLongTakeProfitOrderId(),
- orderId -> {
- longTakeProfitTraderIdParam(
- e,
- null,
- false
- );
- }
- );
- }
- }
- }
- }
-
- // ---- 平仓推送回调 ----
-
- /**
- * 平仓推送回调。由 {@link PositionClosesChannelHandler} 在收到平仓推送时调用。
- *
- * <h3>累加规则</h3>
- * cumulativePnl += pnl。止盈平仓时 pnl > 0,止损平仓时 pnl < 0。
- * 累加后检查停止条件:≥ overallTp 或 ≤ -maxLoss。
- *
- * @param contract 合约名称
- * @param side 平仓方向("long" / "short")
- * @param pnl 本次平仓的盈亏金额
- */
- public void onPositionClose(String contract, String side, BigDecimal pnl) {
- if (state == StrategyState.STOPPED) {
- return;
- }
- cumulativePnl = cumulativePnl.add(pnl);
- updateUnrealizedPnl();
- BigDecimal totalPnl = cumulativePnl.add(unrealizedPnl);
- log.info("[Gate] 已实现:{}, 未实现:{}, 合计:{}",
- cumulativePnl, unrealizedPnl, totalPnl);
- if(totalPnl.compareTo(config.getMaxLoss().negate()) <= 0) {
- String logMessage = StrUtil.format("[Gate] 已达亏损风险值(合计{}), 已实现:{}, 未实现:{}",
- totalPnl, cumulativePnl, unrealizedPnl);
- log.info(logMessage);
-
- DingTalkUtils.getDefault().sendActionCard("风险提醒", logMessage, config.getApiKey(), "");
- }
- }
-
- // ---- 订单推送回调 ----
-
- /**
- * 订单推送回调。由 OrdersChannelHandler 在收到订单更新推送时调用。
- *
- * <h3>处理逻辑</h3>
- * 当订单状态为 finished 且 finish_as 为 filled 时,
- * 从 {@link #currentLongOrderIds} / {@link #currentShortOrderIds} 中匹配订单ID,
- * 取出止盈价格并挂止盈单。匹配成功后从 Map 中移除该条目,防止重复挂单。
- *
- * @param orderId 订单 ID
- * @param status 订单状态(open / finished)
- * @param finishAs 订单结束方式(filled / cancelled / ioc 等)
- */
- public void onOrderUpdate(String orderId, String status, String finishAs) {
- if (!"finished".equals(status) || !"filled".equals(finishAs)) {
- return;
- }
-
- /**
- * 匹配止盈单止盈
- */
- GridElement byLongTakeProfitOrderId = GridElement.findByLongTakeProfitOrderId(orderId);
- if (byLongTakeProfitOrderId != null){
- longTakeProfitTraderIdParam(
- byLongTakeProfitOrderId,
- null,
- false
- );
-// longEntryTraderIdParam(
-// byLongTakeProfitOrderId,
-// null,
-// false
-// );
- }
- GridElement byShortTakeProfitOrderId = GridElement.findByShortTakeProfitOrderId(orderId);
- if (byShortTakeProfitOrderId != null){
- shortTakeProfitTraderIdParam(
- byShortTakeProfitOrderId,
- null,
- false
- );
-// shortEntryTraderIdParam(
-// byShortTakeProfitOrderId,
-// null,
-// false
-// );
- }
-
- /**
- * 匹配挂单
- */
- GridElement longGridElement = GridElement.findByLongOrderId(orderId);
- if (longGridElement != null) {
- if (longGridElement.isHasLongOrder()){
- longEntryTraderIdParam(
- longGridElement,
- null,
- false
- );
- if (longGridElement.getLongTakeProfitOrderId() == null){
- BigDecimal longTp = longGridElement.getLongTraderParam().getTakeProfitPrice();
- if (longTp != null) {
- executor.placeTakeProfit(longTp,
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- ORDER_TYPE_CLOSE_LONG,
- negate(config.getQuantity()),
- (profitId) -> {
- longTakeProfitTraderIdParam(
- longGridElement,
- profitId,
- true
- );
- });
- log.info("[Gate] 多单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, longTp, negate(config.getQuantity()));
- return;
- }
- }
- }
- }
- GridElement shortGridElement = GridElement.findByShortOrderId(orderId);
- if (shortGridElement != null) {
- if (shortGridElement.isHasShortOrder()){
- shortEntryTraderIdParam(
- shortGridElement,
- null,
- false
- );
- if (shortGridElement.getShortTakeProfitOrderId() == null){
- BigDecimal shortTp = shortGridElement.getShortTraderParam().getTakeProfitPrice();
- if (shortTp != null) {
- executor.placeTakeProfit(shortTp,
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- ORDER_TYPE_CLOSE_SHORT,
- config.getQuantity(),
- (profitId) -> {
- shortTakeProfitTraderIdParam(
- shortGridElement,
- profitId,
- true
- );
- });
- log.info("[Gate] 空单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, shortTp, config.getQuantity());
- }
- }
- }
- }
- }
-
- /**
- * 用户私有成交回调。由 {@link com.xcong.excoin.modules.gateApi.wsHandler.handler.UserTradesChannelHandler}
- * 在收到 {@code futures.usertrades} 推送时调用。
- *
- * @param contract 合约名称
- * @param orderId 订单 ID
- * @param price 成交价格
- * @param size 成交数量
- * @param role 用户角色(maker / taker)
- * @param fee 手续费
- */
- public void onUserTrade(String contract, String orderId, BigDecimal price, String size, String role, BigDecimal fee) {
- if (state == StrategyState.STOPPED) {
- return;
- }
- log.info("[Gate] 成交明细, 合约:{}, 订单ID:{}, 价格:{}, 数量:{}, 角色:{}, 手续费:{}",
- contract, orderId, price, size, role, fee);
- }
-
- /**
- * 自动订单(条件单)状态变更回调。
- * 由 {@link com.xcong.excoin.modules.gateApi.wsHandler.handler.AutoOrdersChannelHandler}
- * 在收到 {@code futures.autoorders} 推送时调用。
- *
- * @param orderId 条件单 ID
- * @param status 订单状态(open / finished / cancelled)
- * @param reason 变更原因
- * @param orderType 订单类型(plan-close-long-position 等)
- */
- public void onAutoOrder(String orderId, String status, String reason, String orderType, String tradeId) {
- if (state == StrategyState.STOPPED) {
- return;
- }
- log.info("[Gate] 条件单状态变更, id:{}, status:{}, reason:{}, order_type:{}",
- orderId, status, reason, orderType);
- if (!"finished".equals(status)) {
- return;
- }
-
- GridElement longStopLossElem = GridElement.findByLongStopLossOrderId(orderId);
- if (longStopLossElem != null) {
- handleLongStopLossTriggered(longStopLossElem);
- return;
- }
- GridElement shortStopLossElem = GridElement.findByShortStopLossOrderId(orderId);
- if (shortStopLossElem != null) {
- handleShortStopLossTriggered(shortStopLossElem);
- return;
- }
-
-// GridElement byShortTakeProfitOrderId = GridElement.findByShortTakeProfitOrderId(orderId);
-// if (byShortTakeProfitOrderId != null){
-// shortTakeProfitTraderIdParam(
-// byShortTakeProfitOrderId,
-// null,
-// false
-// );
-// shortEntryTraderIdParam(
-// byShortTakeProfitOrderId,
-// null,
-// false
-// );
-// TPonUserTradeShortEntry(byShortTakeProfitOrderId);
-// }
-// GridElement byLongTakeProfitOrderId = GridElement.findByLongTakeProfitOrderId(orderId);
-// if (byLongTakeProfitOrderId != null){
-// longTakeProfitTraderIdParam(
-// byLongTakeProfitOrderId,
-// null,
-// false
-// );
-// longEntryTraderIdParam(
-// byLongTakeProfitOrderId,
-// null,
-// false
-// );
-// TPonUserTradeLongEntry(byLongTakeProfitOrderId);
-// }
-
- GridElement shortGridElement = GridElement.findByShortOrderId(orderId);
- if (shortGridElement != null) {
- if (shortGridElement.isHasShortOrder() && !tradeId.equals("0")){
- int filledQty = Integer.parseInt(shortGridElement.getShortTraderParam().getQuantity());
- shortEntryTraderIdParam(shortGridElement, null, false);
- extendShortStopLoss(filledQty);
- log.info("[Gate] 空单成交 gridId:{}, qty:{}, 追挂止损", shortGridElement.getId(), filledQty);
- }
- }
- GridElement longGridElement = GridElement.findByLongOrderId(orderId);
- if (longGridElement != null) {
- if (longGridElement.isHasLongOrder() && !tradeId.equals("0")){
- int filledQty = Integer.parseInt(longGridElement.getLongTraderParam().getQuantity());
- longEntryTraderIdParam(longGridElement, null, false);
- extendLongStopLoss(filledQty);
- log.info("[Gate] 多单成交 gridId:{}, qty:{}, 追挂止损", longGridElement.getId(), filledQty);
- }
- }
- }
-
- private void TPonUserTradeShortEntry(GridElement gridElement) {
- if (!isMarginSafe()) {
- log.warn("[Gate] 保证金超限,跳过挂条件单");
- } else {
- // 判断网格是否能开多仓,如果不能则跳过
- GridElement upGridElement = GridElement.findById(gridElement.getUpId());
- if (upGridElement != null){
- BigDecimal upGridPrice = upGridElement.getGridPrice();
- TraderParam upLongTraderParam = upGridElement.getLongTraderParam();
- if (
- !upGridElement.isHasLongOrder() &&
- upGridPrice.compareTo(longEntryPrice) <= 0
- ){
- placeEntryOrderWithPreFlag(upGridElement, true,
- upLongTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- upLongTraderParam.getQuantity());
- }
- }
- }
- }
-
- private void TPonUserTradeLongEntry(GridElement gridElement) {
- if (!isMarginSafe()) {
- log.warn("[Gate] 保证金超限,跳过挂条件单");
- } else {
- // 判断网格是否能开空仓,如果不能则跳过
- GridElement downGridElement = GridElement.findById(gridElement.getDownId());
- if (downGridElement != null){
-
- BigDecimal downGridPrice = downGridElement.getGridPrice();
-
- TraderParam shortTraderParam = downGridElement.getShortTraderParam();
- if (
- !downGridElement.isHasShortOrder() &&
- downGridPrice.compareTo(shortEntryPrice) >= 0
- ){
- placeEntryOrderWithPreFlag(downGridElement, false,
- shortTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- negate(config.getQuantity()));
- }
- }
- }
- }
-
- private void onUserTradeShortEntry(GridElement gridElement) {
- if (!isMarginSafe()) {
- log.warn("[Gate] 保证金超限,跳过挂条件单");
- } else {
- //下一个开仓位置
- GridElement UpGridElement = GridElement.findById(gridElement.getDownId());
- BigDecimal newLongFirst = UpGridElement.getGridPrice();
-
- // 判断网格是否能开空仓,如果不能则跳过
- if (UpGridElement != null) {
-
- if (!UpGridElement.isHasShortOrder() && shortEntryPrice.compareTo(newLongFirst) > 0) {
-
- TraderParam upShortTraderParam = UpGridElement.getShortTraderParam();
- placeEntryOrderWithPreFlag(UpGridElement, false,
- upShortTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- negate(upShortTraderParam.getQuantity()));
- }
- }
- }
- }
-
- private void onUserTradeLongEntry(GridElement gridElement) {
- if (!isMarginSafe()) {
- log.warn("[Gate] 保证金超限,跳过挂条件单");
- } else {
- //下一个开仓位置
- GridElement UpGridElement = GridElement.findById(gridElement.getUpId());
- BigDecimal newLongFirst = UpGridElement.getGridPrice() ;
-
- // 判断网格是否能开多仓,如果不能则跳过
- if (UpGridElement != null) {
-
- if (!UpGridElement.isHasLongOrder() && longEntryPrice.compareTo(newLongFirst) < 0) {
- TraderParam upLongTraderParam = UpGridElement.getLongTraderParam();
- placeEntryOrderWithPreFlag(UpGridElement, true,
- upLongTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- config.getQuantity());
- }
- }
- }
- }
-
- // ---- 网格队列处理 ----
-
- /**
- * 尝试生成网格队列。双基底(多+空)都成交后才触发:
- * <ol>
- * <li>生成空仓价格队列(降序)和多仓价格队列(升序)</li>
- * <li>挂初始多仓条件单(触发价 = 多仓队列首元素,rule=NUMBER_1 ≥触发价时开多),
- * 止盈价 = 触发价 + step,通过 onSuccess 回调将 orderId → 止盈价存入 currentLongOrderIds</li>
- * <li>挂初始空仓条件单(触发价 = 空仓队列首元素,rule=NUMBER_2 ≤触发价时开空),
- * 止盈价 = 触发价 − step,通过 onSuccess 回调将 orderId → 止盈价存入 currentShortOrderIds</li>
- * <li>状态切换为 ACTIVE</li>
- * </ol>
- * 条件单成交后由 {@link #onOrderUpdate} 匹配止盈价并挂止盈条件单。
- */
- private void tryGenerateQueues() {
- if (baseLongOpened && baseShortOpened) {
- generateShortQueue();
- generateLongQueue();
- updateGridElements();
-
- GridElement baseGridElement = GridElement.findById(0);
- TraderParam baseLongTraderParam = config.getBaseLongTraderParam();
- baseGridElement.setLongOrderId(baseLongTraderParam.getEntryOrderId());
- baseGridElement.setHasLongOrder(true);
- TraderParam baseShortTraderParam = config.getBaseShortTraderParam();
- baseGridElement.setShortOrderId(baseShortTraderParam.getEntryOrderId());
- baseGridElement.setHasShortOrder(true);
-
- for (int id = 2; id <= 11; id++) {
- GridElement elem = GridElement.findById(id);
- if (elem == null) {
- continue;
- }
- BigDecimal triggerPrice = elem.getGridPrice();
- int finalId = id;
- executor.placeTakeProfit(
- triggerPrice,
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- ORDER_TYPE_CLOSE_SHORT,
- "1",
- profitId -> {
- elem.setShortStopLossOrderId(profitId);
- GridElement.refreshIndices();
- log.info("[Gate] 空仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
- }
- );
- }
-
- for (int id = -2; id >= -11; id--) {
- GridElement elem = GridElement.findById(id);
- if (elem == null) {
- continue;
- }
- BigDecimal triggerPrice = elem.getGridPrice();
- int finalId = id;
- executor.placeTakeProfit(
- triggerPrice,
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- ORDER_TYPE_CLOSE_LONG,
- "-1",
- profitId -> {
- elem.setLongStopLossOrderId(profitId);
- GridElement.refreshIndices();
- log.info("[Gate] 多仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
- }
- );
- }
-
- log.info("[Gate] 止损单已全部挂完, 空仓止损: 2~11, 多仓止损: -2~-11");
- state = StrategyState.ACTIVE;
- }
- }
-
- /**
- * 更新基座止盈信息,将止盈价、订单ID等写入 TraderParam 并回填到 ID=0 的网格元素中。
- */
- private void longTakeProfitTraderIdParam(
- GridElement baseElement,String profitId, boolean flag
- ) {
- TraderParam tp = baseElement.getLongTraderParam();
- tp.setTakeProfitOrderId(profitId);
- tp.setTakeProfitPlaced(flag);
- baseElement.setLongTakeProfitOrderId(profitId);
- GridElement.refreshIndices();
- }
- private void shortTakeProfitTraderIdParam(
- GridElement baseElement,String profitId, boolean flag
- ) {
- TraderParam tp = baseElement.getShortTraderParam();
- tp.setTakeProfitOrderId(profitId);
- tp.setTakeProfitPlaced(flag);
- baseElement.setShortTakeProfitOrderId(profitId);
- GridElement.refreshIndices();
- }
-
- private void longEntryTraderIdParam(
- GridElement baseElement,String entryId,boolean flag
- ) {
- TraderParam tp = baseElement.getLongTraderParam();
- tp.setEntryOrderId(entryId);
- tp.setEntryOrderPlaced(flag);
- baseElement.setHasLongOrder(flag);
- baseElement.setLongOrderId(entryId);
- GridElement.refreshIndices();
- }
-
- private void shortEntryTraderIdParam(
- GridElement baseElement, String entryId, boolean flag
- ) {
- TraderParam tp = baseElement.getShortTraderParam();
- tp.setEntryOrderId(entryId);
- tp.setEntryOrderPlaced(flag);
- baseElement.setHasShortOrder(flag);
- baseElement.setShortOrderId(entryId);
- GridElement.refreshIndices();
- }
-
- /**
- * 生成空仓价格队列。
- * 以 shortBaseEntryPrice × gridRate 作为绝对步长 step,存到 config。
- * 第1个元素 = shortBaseEntryPrice − step,后续依次递减 step,共 gridQueueSize 个。
- * 队列降序排列(大→小),方便 processShortGrid 中从头遍历。
- */
- private void generateShortQueue() {
- shortPriceQueue.clear();
- int prec = config.getPriceScale();
- BigDecimal step = shortBaseEntryPrice.multiply(config.getGridRate()).setScale(prec, RoundingMode.HALF_UP);
- config.setStep(step);
- BigDecimal elem = shortBaseEntryPrice.subtract(step).setScale(prec, RoundingMode.HALF_UP);
- for (int i = 0; i < config.getGridQueueSize(); i++) {
- shortPriceQueue.add(elem);
- elem = elem.subtract(step).setScale(prec, RoundingMode.HALF_UP);
- if (elem.compareTo(BigDecimal.ZERO) <= 0) {
- break;
- }
- }
- shortPriceQueue.sort((a, b) -> b.compareTo(a));
- log.info("[Gate] 空队列:{}", shortPriceQueue);
- }
-
- /**
- * 生成多仓价格队列。
- * 以 shortBaseEntryPrice + step 为首元素,后续依次递增 step,共 gridQueueSize 个。
- * 队列升序排列(小→大),方便 processLongGrid 中从头遍历。
- */
- private void generateLongQueue() {
- longPriceQueue.clear();
- int prec = config.getPriceScale();
- BigDecimal step = config.getStep();
- BigDecimal elem = shortBaseEntryPrice.add(step).setScale(prec, RoundingMode.HALF_UP);
- for (int i = 0; i < config.getGridQueueSize(); i++) {
- longPriceQueue.add(elem);
- elem = elem.add(step).setScale(prec, RoundingMode.HALF_UP);
- }
- longPriceQueue.sort(BigDecimal::compareTo);
- log.info("[Gate] 多队列:{}", longPriceQueue);
- }
-
- /**
- * 根据当前多空价格队列同步构建网格元素列表,写入 config。
- *
- * <h3>ID 分配规则</h3>
- * <ul>
- * <li>空仓队列:id 从 -1 自减(-1, -2, -3...),第一个元素 upId=0,最后一个 downId=null</li>
- * <li>位置 0:gridPrice=shortBaseEntryPrice,upId=-1,downId=1,其数据在基座开仓时更新</li>
- * <li>多仓队列:id 从 1 自增(1, 2, 3...),第一个元素 upId=0,最后一个 downId=null</li>
- * </ul>
- *
- * <h3>链表关系</h3>
- * 所有元素通过 upId/downId 串成一条双向链表:
- * ... → -3 → -2 → -1 → 0 → 1 → 2 → 3 → ...
- */
- private void updateGridElements() {
- List<GridElement> elements = new ArrayList<>();
- int shortSize = shortPriceQueue.size();
- int longSize = longPriceQueue.size();
- //根据精度转换成小数
- int prec = config.getPriceScale();
-// BigDecimal minTick = BigDecimal.ONE.scaleByPowerOfTen(-prec);
-// BigDecimal step = config.getStep().subtract(minTick);
- BigDecimal step = config.getStep();
- String qty = config.getQuantity();
-
- // 空仓队列:id 从 -1 自减, shortPriceQueue[i] → id=-(i+1)
- for (int i = 0; i < shortSize; i++) {
- int id = -(i + 1);
- Integer upId = (i == 0) ? 0 : id + 1;
- Integer downId = (i == shortSize - 1) ? null : id - 1;
- BigDecimal price = shortPriceQueue.get(i);
- TraderParam longParam = TraderParam.builder()
- .direction(TraderParam.Direction.LONG)
- .entryPrice(price)
- .takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP))
- .quantity(qty)
- .build();
- TraderParam shortParam = TraderParam.builder()
- .direction(TraderParam.Direction.SHORT)
- .entryPrice(price)
- .takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP))
- .quantity(qty)
- .build();
- elements.add(GridElement.builder()
- .id(id)
- .gridPrice(price)
- .upId(upId)
- .downId(downId)
- .longTraderParam(longParam)
- .shortTraderParam(shortParam)
- .build());
- }
-
- // 位置 0:基底价格,数据在基座开仓时更新
- {
- BigDecimal price = shortBaseEntryPrice;
- TraderParam longParam = TraderParam.builder()
- .direction(TraderParam.Direction.LONG)
- .entryPrice(price)
- .takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP))
- .quantity(qty)
- .build();
- TraderParam shortParam = TraderParam.builder()
- .direction(TraderParam.Direction.SHORT)
- .entryPrice(price)
- .takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP))
- .quantity(qty)
- .build();
- elements.add(GridElement.builder()
- .id(0)
- .gridPrice(price)
- .upId(shortSize > 0 ? 1 : null)
- .downId(longSize > 0 ? -1 : null)
- .longTraderParam(longParam)
- .shortTraderParam(shortParam)
- .build());
- }
-
- // 多仓队列:id 从 1 自增, longPriceQueue[i] → id=i+1
- for (int i = 0; i < longSize; i++) {
- int id = i + 1;
- Integer downId = (i == 0) ? 0 : id - 1;
- Integer upId = (i == longSize - 1) ? null : id + 1;
- BigDecimal price = longPriceQueue.get(i);
- TraderParam longParam = TraderParam.builder()
- .direction(TraderParam.Direction.LONG)
- .entryPrice(price)
- .takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP))
- .quantity(qty)
- .build();
- TraderParam shortParam = TraderParam.builder()
- .direction(TraderParam.Direction.SHORT)
- .entryPrice(price)
- .takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP))
- .quantity(qty)
- .build();
- elements.add(GridElement.builder()
- .id(id)
- .gridPrice(price)
- .upId(upId)
- .downId(downId)
- .longTraderParam(longParam)
- .shortTraderParam(shortParam)
- .build());
- }
-
- config.setGridElements(elements);
- log.info("[Gate] 网格元素列表已构建, 共{}个元素 (空仓:{} 位置:0 多仓:{})", elements.size(), shortSize, longSize);
- }
-
- private void processShortGrid(BigDecimal currentPrice) {
- int prec = config.getPriceScale();
- List<BigDecimal> matched = new ArrayList<>();
- synchronized (shortPriceQueue) {
- for (BigDecimal p : shortPriceQueue) {
- if (p.compareTo(currentPrice) >= 0) {
- matched.add(p);
- } else {
- break;
- }
- }
- }
- if (matched.isEmpty()) {
- return;
- }
- log.info("[Gate] 空仓队列触发, 匹配{}个元素, 当前价:{}", matched.size(), currentPrice);
-
- synchronized (shortPriceQueue) {
- shortPriceQueue.removeAll(matched);
- BigDecimal min = shortPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : shortPriceQueue.get(shortPriceQueue.size() - 1);
- BigDecimal gridStep = config.getStep();
- for (int i = 0; i < matched.size(); i++) {
- min = min.subtract(gridStep).setScale(prec, RoundingMode.HALF_UP);
- shortPriceQueue.add(min);
- }
- shortPriceQueue.sort((a, b) -> b.compareTo(a));
- }
-
- synchronized (longPriceQueue) {
- BigDecimal first = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(0);
- BigDecimal gridStep = config.getStep();
- for (int i = 1; i <= matched.size(); i++) {
- BigDecimal elem = first.subtract(gridStep.multiply(BigDecimal.valueOf(i))).setScale(prec, RoundingMode.HALF_UP);
- longPriceQueue.add(elem);
- }
- longPriceQueue.sort(BigDecimal::compareTo);
- while (longPriceQueue.size() > config.getGridQueueSize()) {
- longPriceQueue.remove(longPriceQueue.size() - 1);
- }
- }
-
- if (!isMarginSafe()) {
- log.warn("[Gate] 保证金超限,跳过挂条件单");
- } else {
-
- /**
- * 下一个开仓位置
- * 获取队列第一个元素的价格对应的网格
- * 判断网格是否能开空仓,如果不能则跳过
- * 前进方向挂空仓条件单
- * 后置方向挂多空条件单
- */
- //下一个开仓位置
- BigDecimal newLongFirst = shortPriceQueue.get(0);
- GridElement UpGridElement = GridElement.findByPrice(newLongFirst);
-
- // 判断网格是否能开空仓,如果不能则跳过
- if (UpGridElement != null) {
-
-// if (!UpGridElement.isHasShortOrder() && shortEntryPrice.compareTo(newLongFirst) > 0) {
-//
-// TraderParam upShortTraderParam = UpGridElement.getShortTraderParam();
-// placeEntryOrderWithPreFlag(UpGridElement, false,
-// upShortTraderParam.getEntryPrice(),
-// FuturesPriceTrigger.RuleEnum.NUMBER_2,
-// negate(upShortTraderParam.getQuantity()));
-// }
- int i = UpGridElement.getId() + 2;
- GridElement downGridElement = GridElement.findById(i);
- if (downGridElement != null){
-
- BigDecimal downGridPrice = downGridElement.getGridPrice();
-
-// TraderParam downShortTraderParam = downGridElement.getShortTraderParam();
-// if (
-// !downGridElement.isHasShortOrder() &&
-// downGridPrice.compareTo(longEntryPrice) <= 0 &&
-// downGridPrice.compareTo(shortEntryPrice) >= 0
-// ){
-// placeEntryOrderWithPreFlag(downGridElement, false,
-// downShortTraderParam.getEntryPrice(),
-// FuturesPriceTrigger.RuleEnum.NUMBER_1,
-// negate(downShortTraderParam.getQuantity()));
-//
-// }
-
- TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
- if (
- !downGridElement.isHasLongOrder() &&
- downGridPrice.compareTo(longEntryPrice) <= 0
- ){
- placeEntryOrderWithPreFlag(downGridElement, true,
- downLongTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- downLongTraderParam.getQuantity());
- }
- }
- }
- }
- }
-
- private void processLongGrid(BigDecimal currentPrice) {
- int prec = config.getPriceScale();
- List<BigDecimal> matched = new ArrayList<>();
- synchronized (longPriceQueue) {
- for (BigDecimal p : longPriceQueue) {
- if (p.compareTo(currentPrice) <= 0) {
- matched.add(p);
- } else {
- break;
- }
- }
- }
- if (matched.isEmpty()) {
- return;
- }
-
- log.info("[Gate] 多仓队列触发, 匹配{}个元素, 当前价:{}", matched.size(), currentPrice);
-
- /**
- * 匹配到元素后,
- * 多仓队列更新
- * 空仓队列更新
- */
- synchronized (longPriceQueue) {
- longPriceQueue.removeAll(matched);
- BigDecimal max = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(longPriceQueue.size() - 1);
- BigDecimal gridStep = config.getStep();
- for (int i = 0; i < matched.size(); i++) {
- max = max.add(gridStep).setScale(prec, RoundingMode.HALF_UP);
- longPriceQueue.add(max);
- }
- longPriceQueue.sort(BigDecimal::compareTo);
- }
- synchronized (shortPriceQueue) {
- BigDecimal first = shortPriceQueue.isEmpty() ? matched.get(0) : shortPriceQueue.get(0);
- BigDecimal gridStep = config.getStep();
- for (int i = 1; i <= matched.size(); i++) {
- BigDecimal elem = first.add(gridStep.multiply(BigDecimal.valueOf(i))).setScale(prec, RoundingMode.HALF_UP);
- shortPriceQueue.add(elem);
- }
- shortPriceQueue.sort((a, b) -> b.compareTo(a));
- while (shortPriceQueue.size() > config.getGridQueueSize()) {
- shortPriceQueue.remove(shortPriceQueue.size() - 1);
- }
- }
-
- if (!isMarginSafe()) {
- log.warn("[Gate] 保证金超限,跳过挂条件单");
- } else {
-
- /**
- * 下一个开仓位置
- * 获取队列第一个元素的价格对应的网格
- * 判断网格是否能开多仓,如果不能则跳过
- * 前进方向挂多仓条件单
- * 后置方向挂多空条件单
- */
- //下一个开仓位置
- BigDecimal newLongFirst = longPriceQueue.get(0);
- GridElement UpGridElement = GridElement.findByPrice(newLongFirst);
-
- // 判断网格是否能开多仓,如果不能则跳过
- if (UpGridElement != null) {
-
-// if (!UpGridElement.isHasLongOrder() && longEntryPrice.compareTo(newLongFirst) < 0) {
-// TraderParam upLongTraderParam = UpGridElement.getLongTraderParam();
-// placeEntryOrderWithPreFlag(UpGridElement, true,
-// upLongTraderParam.getEntryPrice(),
-// FuturesPriceTrigger.RuleEnum.NUMBER_1,
-// config.getQuantity());
-// }
-
- int i = UpGridElement.getId() - 2;
- GridElement downGridElement = GridElement.findById(i);
- if (downGridElement != null){
-
- BigDecimal downGridPrice = downGridElement.getGridPrice();
-
-// TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
-// if (
-// !downGridElement.isHasLongOrder() &&
-// downGridPrice.compareTo(shortEntryPrice) >= 0 &&
-// downGridPrice.compareTo(longEntryPrice) <= 0
-// ){
-// placeEntryOrderWithPreFlag(downGridElement, true,
-// downLongTraderParam.getEntryPrice(),
-// FuturesPriceTrigger.RuleEnum.NUMBER_2,
-// config.getQuantity());
-//
-// }
-
- TraderParam shortTraderParam = downGridElement.getShortTraderParam();
- if (
- !downGridElement.isHasShortOrder() &&
- downGridPrice.compareTo(shortEntryPrice) >= 0
- ){
-
- placeEntryOrderWithPreFlag(downGridElement, false,
- shortTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- negate(config.getQuantity()));
- }
- }
- }
- }
- }
-
- private void handleLongStopLossTriggered(GridElement gridElement) {
- int gridId = gridElement.getId();
- int N = Math.abs(gridId);
- gridElement.setLongStopLossOrderId(null);
- log.info("[Gate] 多仓止损触发 gridId:{}, 开始追单", gridId);
-
- int newEntryGridId = -(N - 1);
-
- GridElement newEntryGrid = GridElement.findById(newEntryGridId);
- if (newEntryGrid == null) {
- log.warn("[Gate] 多仓止损触发 but gridId:{} 不存在", newEntryGridId);
- GridElement.refreshIndices();
- return;
- }
-
- if (N > 2) {
- int cancelGridId = -(N - 2);
- GridElement cancelGrid = GridElement.findById(cancelGridId);
- if (cancelGrid != null && cancelGrid.isHasLongOrder()) {
- executor.cancelConditionalOrder(cancelGrid.getLongOrderId(), oid -> {
- longEntryTraderIdParam(cancelGrid, null, false);
- log.info("[Gate] 多仓止损触发, 取消gridId:{}的多单", cancelGridId);
- });
- }
- }
-
- BigDecimal triggerPrice = newEntryGrid.getGridPrice();
- BigDecimal priceDiff = longEntryPrice.subtract(triggerPrice).abs();
- int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
- entryQty = Math.max(1, entryQty);
- String size = String.valueOf(entryQty);
- log.info("[Gate] 多仓止损触发 gridId:{}, 在gridId:{}挂{}张多单, 均价:{}, 价差:{}, 步长:{}",
- gridId, newEntryGridId, entryQty, longEntryPrice, priceDiff, config.getStep());
- newEntryGrid.getLongTraderParam().setQuantity(size);
- placeEntryOrderWithPreFlag(newEntryGrid, true, triggerPrice,
- FuturesPriceTrigger.RuleEnum.NUMBER_1, size);
- }
-
- private void handleShortStopLossTriggered(GridElement gridElement) {
- int gridId = gridElement.getId();
- int N = gridId;
- gridElement.setShortStopLossOrderId(null);
- log.info("[Gate] 空仓止损触发 gridId:{}, 开始追单", gridId);
-
- int newEntryGridId = N - 1;
-
- GridElement newEntryGrid = GridElement.findById(newEntryGridId);
- if (newEntryGrid == null) {
- log.warn("[Gate] 空仓止损触发 but gridId:{} 不存在", newEntryGridId);
- GridElement.refreshIndices();
- return;
- }
-
- if (N > 2) {
- int cancelGridId = N - 2;
- GridElement cancelGrid = GridElement.findById(cancelGridId);
- if (cancelGrid != null && cancelGrid.isHasShortOrder()) {
- executor.cancelConditionalOrder(cancelGrid.getShortOrderId(), oid -> {
- shortEntryTraderIdParam(cancelGrid, null, false);
- log.info("[Gate] 空仓止损触发, 取消gridId:{}的空单", cancelGridId);
- });
- }
- }
-
-
-
- BigDecimal triggerPrice = newEntryGrid.getGridPrice();
- BigDecimal priceDiff = shortEntryPrice.subtract(triggerPrice).abs();
- int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
- entryQty = Math.max(1, entryQty);
- String size = String.valueOf(entryQty);
- log.info("[Gate] 空仓止损触发 gridId:{}, 在gridId:{}挂{}张空单, 均价:{}, 价差:{}, 步长:{}",
- gridId, newEntryGridId, entryQty, shortEntryPrice, priceDiff, config.getStep());
- newEntryGrid.getShortTraderParam().setQuantity(size);
- placeEntryOrderWithPreFlag(newEntryGrid, false, triggerPrice,
- FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(size));
- }
-
- private void extendLongStopLoss(int filledQty) {
- int furthestSlId = 0;
- for (GridElement e : config.getGridElements()) {
- if (e.getLongStopLossOrderId() != null && e.getId() < furthestSlId) {
- furthestSlId = e.getId();
- }
- }
- if (furthestSlId == 0) {
- furthestSlId = -11;
- }
- log.info("[Gate] 多仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
- for (int i = 0; i < filledQty; i++) {
- int newSlId = furthestSlId - i - 1;
- GridElement elem = GridElement.findById(newSlId);
- if (elem == null) {
- continue;
- }
- BigDecimal triggerPrice = elem.getGridPrice();
- int finalSlId = newSlId;
- executor.placeTakeProfit(
- triggerPrice,
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- ORDER_TYPE_CLOSE_LONG,
- "-1",
- profitId -> {
- elem.setLongStopLossOrderId(profitId);
- GridElement.refreshIndices();
- log.info("[Gate] 多仓止损追加, gridId:{}, 触发价:{}, stopLossId:{}", finalSlId, triggerPrice, profitId);
- }
- );
- }
- }
-
- private void extendShortStopLoss(int filledQty) {
- int furthestSlId = 0;
- for (GridElement e : config.getGridElements()) {
- if (e.getShortStopLossOrderId() != null && e.getId() > furthestSlId) {
- furthestSlId = e.getId();
- }
- }
- if (furthestSlId == 0) {
- furthestSlId = 11;
- }
- log.info("[Gate] 空仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
- for (int i = 0; i < filledQty; i++) {
- int newSlId = furthestSlId + i + 1;
- GridElement elem = GridElement.findById(newSlId);
- if (elem == null) {
- continue;
- }
- BigDecimal triggerPrice = elem.getGridPrice();
- int finalSlId = newSlId;
- executor.placeTakeProfit(
- triggerPrice,
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- ORDER_TYPE_CLOSE_SHORT,
- "1",
- profitId -> {
- elem.setShortStopLossOrderId(profitId);
- GridElement.refreshIndices();
- log.info("[Gate] 空仓止损追加, gridId:{}, 触发价:{}, stopLossId:{}", finalSlId, triggerPrice, profitId);
- }
- );
- }
- }
-
- private void checkProfitAndReset() {
- try {
- FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
- BigDecimal unrealisedPnl = new BigDecimal(account.getCrossUnrealisedPnl());
- BigDecimal available = new BigDecimal(account.getCrossAvailable());
- BigDecimal totalEquity = unrealisedPnl.add(available);
- BigDecimal target = initialPrincipal.add(config.getExpectedProfit());
- log.info("[Gate] 盈亏检查 cross_unrealised_pnl:{}, cross_available:{}, 合计:{}, 目标:{}",
- unrealisedPnl, available, totalEquity, target);
- if (totalEquity.compareTo(target) > 0) {
- log.info("[Gate] 盈亏达标({}>{}),重置策略", totalEquity, target);
- state = StrategyState.STOPPED;
- closeExistingPositions();
- futuresApi.cancelPriceTriggeredOrderList(SETTLE, config.getContract());
- startGrid();
- }
- } catch (Exception e) {
- log.warn("[Gate] 盈亏检查失败", e);
- }
- }
-
- private void handlePositionZeroAndReset(String direction) {
- state = StrategyState.STOPPED;
- try {
- futuresApi.cancelPriceTriggeredOrderList(SETTLE, config.getContract());
- } catch (Exception e) {
- log.warn("[Gate] {}持仓归零后取消条件单失败", direction, e);
- }
- closeExistingPositions();
- startGrid();
- }
-
- // ---- 保证金安全阀 ----
-
- /**
- * 保证金安全阀检查。
- *
- * <p>实时查询当前保证金占用额(positionInitialMargin),计算其占初始本金的比例。
- * 比例 ≥ marginRatioLimit(默认 20%)时拒绝开仓,但仍照常更新队列。
- *
- * <p>查询失败时默认放行(返回 true),避免因 REST API 异常导致策略完全停滞。
- *
- * @return true=安全可开仓 / false=保证金超限跳过开仓
- */
- private boolean isMarginSafe() {
- try {
- FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
- BigDecimal margin = new BigDecimal(account.getPositionInitialMargin());
- BigDecimal ratio = margin.divide(initialPrincipal, 4, RoundingMode.HALF_UP);
- log.debug("[Gate] 保证金比例: {}/{}={}", margin, initialPrincipal, ratio);
- return ratio.compareTo(config.getMarginRatioLimit()) < 0;
- } catch (Exception e) {
- log.warn("[Gate] 查保证金失败,默认放行", e);
- return true;
- }
- }
-
- // ---- 工具 ----
-
- /**
- * 取反字符串数字。如 "1" → "-1","-2" → "2"。
- * 用于开空单时将正数张数转为负数。
- */
- private String negate(String qty) {
- return qty.startsWith("-") ? qty.substring(1) : "-" + qty;
- }
-
- /**
- * 预设标志位后提交条件开仓单,防止异步回调导致的竞态重复挂单。
- *
- * <p>在调用 {@link GateTradeExecutor#placeConditionalEntryOrder} 之前同步设置
- * {@code isHasLongOrder / isHasShortOrder},关闭 WS 线程与 Executor 线程之间的
- * 检查-下单时间窗口。API 失败时自动回滚标志位。
- *
- * @param gridElement 目标网格元素
- * @param isLong true=多仓下单,false=空仓下单
- * @param triggerPrice 触发价
- * @param rule 触发规则
- * @param size 开仓张数
- */
- private void placeEntryOrderWithPreFlag(GridElement gridElement, boolean isLong,
- BigDecimal triggerPrice,
- FuturesPriceTrigger.RuleEnum rule,
- String size) {
- if (isLong) {
- gridElement.setHasLongOrder(true);
- } else {
- gridElement.setHasShortOrder(true);
- }
- executor.placeConditionalEntryOrder(triggerPrice, rule, size,
- orderId -> {
- if (isLong) {
- longEntryTraderIdParam(gridElement, orderId, true);
- } else {
- shortEntryTraderIdParam(gridElement, orderId, true);
- }
- },
- () -> {
- if (isLong) {
- gridElement.setHasLongOrder(false);
- gridElement.setLongOrderId(null);
- } else {
- gridElement.setHasShortOrder(false);
- gridElement.setShortOrderId(null);
- }
- GridElement.refreshIndices();
- log.warn("[Gate] 条件单创建失败,回滚标志位 gridId:{}, isLong:{}", gridElement.getId(), isLong);
- }
- );
- }
-
- /**
- * 根据持仓和当前价格计算未实现盈亏。
- *
- * <h3>正向合约公式</h3>
- * <pre>
- * 多仓: 持仓量 × 合约乘数 × (计价价格 − 开仓均价)
- * 空仓: 持仓量 × 合约乘数 × (开仓均价 − 计价价格)
- * </pre>
- * 计价价格由 {@link GateConfig.PnLPriceMode} 决定:LAST_PRICE 用最新成交价,MARK_PRICE 用标记价格。
- */
- private void updateUnrealizedPnl() {
- BigDecimal price = resolvePnlPrice();
- if (price == null || price.compareTo(BigDecimal.ZERO) == 0) {
- return;
- }
- BigDecimal multiplier = config.getContractMultiplier();
- BigDecimal longPnl = BigDecimal.ZERO;
- BigDecimal shortPnl = BigDecimal.ZERO;
- if (longPositionSize.compareTo(BigDecimal.ZERO) > 0 && longEntryPrice.compareTo(BigDecimal.ZERO) > 0) {
- longPnl = longPositionSize.multiply(multiplier).multiply(price.subtract(longEntryPrice));
- }
- if (shortPositionSize.compareTo(BigDecimal.ZERO) > 0 && shortEntryPrice.compareTo(BigDecimal.ZERO) > 0) {
- shortPnl = shortPositionSize.multiply(multiplier).multiply(shortEntryPrice.subtract(price));
- }
- unrealizedPnl = longPnl.add(shortPnl);
-
- log.info("[Gate] 未实现盈亏: {}", unrealizedPnl);
- }
-
- /**
- * 根据配置的 PnLPriceMode 返回计价价格。
- * MARK_PRICE 模式优先使用标记价格(外部注入),未注入时回退到最新成交价。
- *
- * @return 计价价格,可能为 null
- */
- private BigDecimal resolvePnlPrice() {
- if (config.getUnrealizedPnlPriceMode() == GateConfig.PnLPriceMode.MARK_PRICE
- && markPrice.compareTo(BigDecimal.ZERO) > 0) {
- return markPrice;
- }
- return lastKlinePrice;
- }
-
- /** @return 最新 K 线价格(每次 onKline 更新) */
- public BigDecimal getLastKlinePrice() { return lastKlinePrice; }
- /** 设置标记价格(外部注入,MARK_PRICE 模式时用于盈亏计算) */
- public void setMarkPrice(BigDecimal markPrice) { this.markPrice = markPrice; }
- /** @return 策略是否处于活跃状态(非 STOPPED 且非 WAITING_KLINE) */
- public boolean isStrategyActive() { return state != StrategyState.STOPPED && state != StrategyState.WAITING_KLINE; }
- /** @return 累计已实现盈亏(平仓推送驱动累加) */
- public BigDecimal getCumulativePnl() { return cumulativePnl; }
- /** @return 当前未实现盈亏(每根 K 线实时计算) */
- public BigDecimal getUnrealizedPnl() { return unrealizedPnl; }
- /** @return Gate 用户 ID(用于私有频道订阅 payload) */
- public Long getUserId() { return userId; }
- /** @return 当前策略状态 */
- public StrategyState getState() { return state; }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
deleted file mode 100644
index c3fe3ab..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
+++ /dev/null
@@ -1,362 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.wsHandler.GateChannelHandler;
-import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.handshake.ServerHandshake;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Gate WebSocket 连接管理器。
- *
- * <h3>职责</h3>
- * 负责 TCP 连接的建立、维持和恢复。频道逻辑(订阅/解析)全部委托给 {@link GateChannelHandler} 实现类。
- *
- * <h3>生命周期</h3>
- * <pre>
- * init() → connect() → startHeartbeat()
- * destroy() → unsubscribe 所有 handler → closeBlocking() → shutdown 线程池
- * onClose() → reconnectWithBackoff() (最多 3 次,指数退避)
- * </pre>
- *
- * <h3>消息路由</h3>
- * <pre>
- * onMessage → handleMessage:
- * 1. futures.pong → cancelPongTimeout
- * 2. subscribe/unsubscribe → 日志
- * 3. error → 错误日志
- * 4. update/all → 遍历 channelHandlers → handler.handleMessage(response)
- * </pre>
- *
- * <h3>心跳机制</h3>
- * 采用双重检测:TCP 层的 WebSocket ping/pong + 应用层 futures.ping/futures.pong。
- * 10 秒未收到任何消息 → 发送 futures.ping;25 秒周期检查。
- *
- * <h3>线程安全</h3>
- * 连接状态用 AtomicBoolean(isConnected, isConnecting, isInitialized)。
- * 消息时间戳用 AtomicReference。心跳任务用 synchronized 保护。
- *
- * @author Administrator
- */
-@SuppressWarnings("ALL")
-@Slf4j
-public class GateKlineWebSocketClient {
-
- private static final String FUTURES_PING = "futures.ping";
- private static final String FUTURES_PONG = "futures.pong";
- private static final int HEARTBEAT_TIMEOUT = 10;
-
- /** WebSocket 地址,由 GateConfig 提供 */
- private final String wsUrl;
-
- /** Java-WebSocket 客户端实例 */
- private WebSocketClient webSocketClient;
- /** 心跳检测调度器 */
- private ScheduledExecutorService heartbeatExecutor;
- /** 心跳超时 Future */
- private volatile ScheduledFuture<?> pongTimeoutFuture;
- /** 最后收到消息的时间戳(毫秒) */
- private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
-
- /** 连接状态 */
- private final AtomicBoolean isConnected = new AtomicBoolean(false);
- /** 连接中标记,防重入 */
- private final AtomicBoolean isConnecting = new AtomicBoolean(false);
- /** 初始化标记,防重复 init */
- private final AtomicBoolean isInitialized = new AtomicBoolean(false);
-
- /** 频道处理器列表,通过 addChannelHandler 注册 */
- private final List<GateChannelHandler> channelHandlers = new ArrayList<>();
-
- /** 重连等异步任务的缓存线程池(daemon 线程) */
- private final ExecutorService sharedExecutor = Executors.newCachedThreadPool(r -> {
- Thread t = new Thread(r, "gate-ws-worker");
- t.setDaemon(true);
- return t;
- });
-
- /**
- * @param wsUrl Gate WebSocket 地址(由 {@link GateConfig#getWsUrl()} 提供)
- */
- public GateKlineWebSocketClient(String wsUrl) {
- this.wsUrl = wsUrl;
- }
-
- /**
- * 注册频道处理器。需在 init() 前调用。
- *
- * @param handler 实现了 {@link GateChannelHandler} 接口的频道处理器
- */
- public void addChannelHandler(GateChannelHandler handler) {
- channelHandlers.add(handler);
- }
-
- /**
- * 初始化:建立 WebSocket 连接 → 启动心跳检测。
- * 使用 {@code AtomicBoolean} 防重入,同一实例只允许初始化一次。
- */
- public void init() {
- if (!isInitialized.compareAndSet(false, true)) {
- log.warn("[WS] 已初始化过,跳过重复初始化");
- return;
- }
- connect();
- startHeartbeat();
- }
-
- /**
- * 销毁:取消所有频道订阅 → 关闭 WebSocket 连接 → 关闭线程池。
- *
- * <h3>执行顺序</h3>
- * 先取消订阅(等待 500ms 确保发送完成),再 closeBlocking 关闭连接,
- * 最后 shutdown 线程池。先关连接再关线程池,避免 onClose 回调中的重连任务访问已关闭的线程池。
- */
- public void destroy() {
- log.info("[WS] 开始销毁...");
-
- if (webSocketClient != null && webSocketClient.isOpen()) {
- for (GateChannelHandler handler : channelHandlers) {
- handler.unsubscribe(webSocketClient);
- }
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("[WS] 取消订阅等待被中断");
- }
- }
-
- if (webSocketClient != null && webSocketClient.isOpen()) {
- try {
- webSocketClient.closeBlocking();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("[WS] 关闭连接时被中断");
- }
- }
-
- if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
- sharedExecutor.shutdown();
- }
-
- shutdownExecutorGracefully(heartbeatExecutor);
- if (pongTimeoutFuture != null) {
- pongTimeoutFuture.cancel(true);
- }
- shutdownExecutorGracefully(sharedExecutor);
-
- log.info("[WS] 销毁完成");
- }
-
- /**
- * 建立 WebSocket 连接。使用 SSLContext 配置 TLS 协议。
- *
- * <h3>连接成功回调</h3>
- * <ol>
- * <li>设置 isConnected=true,isConnecting=false</li>
- * <li>重置心跳计时器</li>
- * <li>依次订阅所有已注册的频道处理器</li>
- * <li>发送首次 ping</li>
- * </ol>
- *
- * <h3>连接关闭回调</h3>
- * 设置断连状态 → 取消心跳超时 → 异步触发指数退避重连(最多3次)。
- *
- * <h3>线程安全</h3>
- * 使用 {@code AtomicBoolean.isConnecting} 防止并发重连。
- */
- private void connect() {
- if (isConnecting.get() || !isConnecting.compareAndSet(false, true)) {
- log.info("[WS] 连接进行中,跳过重复请求");
- return;
- }
- try {
- SSLConfig.configureSSL();
- System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
- URI uri = new URI(wsUrl);
- if (webSocketClient != null) {
- try { webSocketClient.closeBlocking(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
- }
- webSocketClient = new WebSocketClient(uri) {
- @Override
- public void onOpen(ServerHandshake handshake) {
- log.info("[WS] 连接成功");
- isConnected.set(true);
- isConnecting.set(false);
- if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
- resetHeartbeatTimer();
- for (GateChannelHandler handler : channelHandlers) {
- handler.subscribe(webSocketClient);
- }
- sendPing();
- } else {
- log.warn("[WS] 应用正在关闭,忽略连接成功回调");
- }
- }
-
- @Override
- public void onMessage(String message) {
- lastMessageTime.set(System.currentTimeMillis());
- handleMessage(message);
- resetHeartbeatTimer();
- }
-
- @Override
- public void onClose(int code, String reason, boolean remote) {
- log.warn("[WS] 连接关闭, code:{}, reason:{}", code, reason);
- isConnected.set(false);
- isConnecting.set(false);
- cancelPongTimeout();
- if (sharedExecutor != null && !sharedExecutor.isShutdown() && !sharedExecutor.isTerminated()) {
- sharedExecutor.execute(() -> {
- try { reconnectWithBackoff(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { log.error("[WS] 重连失败", e); }
- });
- } else {
- log.warn("[WS] 线程池已关闭,不执行重连");
- }
- }
-
- @Override
- public void onError(Exception ex) {
- log.error("[WS] 发生错误", ex);
- isConnected.set(false);
- }
- };
- webSocketClient.connect();
- } catch (URISyntaxException e) {
- log.error("[WS] URI格式错误", e);
- isConnecting.set(false);
- }
- }
-
- /**
- * 消息分发:先处理系统事件(pong/subscribe/error),
- * 再把 update/all 事件路由到各 channelHandler。
- * <p>每个 handler 内部通过 channel 名称做二次匹配,匹配成功返回 true 则停止遍历。
- */
- private void handleMessage(String message) {
- try {
- JSONObject response = JSON.parseObject(message);
- String channel = response.getString("channel");
- String event = response.getString("event");
-
- if (FUTURES_PONG.equals(channel)) {
- log.debug("[WS] 收到 pong 响应");
- cancelPongTimeout();
- return;
- }
- if ("subscribe".equals(event)) {
- log.info("[WS] {} 订阅成功: {}", channel, response.getJSONObject("result"));
- return;
- }
- if ("unsubscribe".equals(event)) {
- log.info("[WS] {} 取消订阅成功", channel);
- return;
- }
- if ("error".equals(event)) {
- JSONObject error = response.getJSONObject("error");
- log.error("[WS] {} 错误, code:{}, msg:{}",
- channel,
- error != null ? error.getInteger("code") : "N/A",
- error != null ? error.getString("message") : response.getString("msg"));
- return;
- }
- if ("update".equals(event) || "all".equals(event)) {
- for (GateChannelHandler handler : channelHandlers) {
- if (handler.handleMessage(response)) return;
- }
- }
- } catch (Exception e) {
- log.error("[WS] 处理消息失败: {}", message, e);
- }
- }
-
- // ---- heartbeat ----
-
- /**
- * 启动心跳检测器。
- * 使用单线程 ScheduledExecutor,每 25 秒检查一次心跳超时。
- */
- private void startHeartbeat() {
- if (heartbeatExecutor != null && !heartbeatExecutor.isTerminated()) heartbeatExecutor.shutdownNow();
- heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> { Thread t = new Thread(r, "gate-ws-heartbeat"); t.setDaemon(true); return t; });
- heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout, 25, 25, TimeUnit.SECONDS);
- }
-
- /**
- * 重置心跳计时器:取消旧超时任务,提交新的 10 秒超时检测。
- */
- private synchronized void resetHeartbeatTimer() {
- cancelPongTimeout();
- if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) {
- pongTimeoutFuture = heartbeatExecutor.schedule(this::checkHeartbeatTimeout, HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
- }
- }
-
- /**
- * 检查心跳超时:如果距离上次收到消息超过 10 秒,主动发送 futures.ping。
- */
- private void checkHeartbeatTimeout() {
- if (!isConnected.get()) return;
- if (System.currentTimeMillis() - lastMessageTime.get() >= HEARTBEAT_TIMEOUT * 1000L) sendPing();
- }
-
- /**
- * 发送应用层 futures.ping 消息。
- */
- private void sendPing() {
- try {
- if (webSocketClient != null && webSocketClient.isOpen()) {
- JSONObject pingMsg = new JSONObject();
- pingMsg.put("time", System.currentTimeMillis() / 1000);
- pingMsg.put("channel", FUTURES_PING);
- webSocketClient.send(pingMsg.toJSONString());
- log.debug("[WS] 发送 ping 请求");
- }
- } catch (Exception e) { log.warn("[WS] 发送 ping 失败", e); }
- }
-
- /**
- * 取消心跳超时检测任务。
- */
- private synchronized void cancelPongTimeout() {
- if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) pongTimeoutFuture.cancel(true);
- }
-
- // ---- reconnect ----
-
- /**
- * 指数退避重连。初始延迟 5 秒,每次翻倍,最多重试 3 次。
- *
- * @throws InterruptedException 线程被中断
- */
- private void reconnectWithBackoff() throws InterruptedException {
- int attempt = 0, maxAttempts = 3;
- long delayMs = 5000;
- while (attempt < maxAttempts) {
- try { Thread.sleep(delayMs); connect(); return; } catch (Exception e) { log.warn("[WS] 第{}次重连失败", attempt + 1, e); delayMs *= 2; attempt++; }
- }
- log.error("[WS] 超过最大重试次数({}),放弃重连", maxAttempts);
- }
-
- /**
- * 优雅关闭线程池:先 shutdown,等待 5 秒,超时则 shutdownNow 强制中断。
- *
- * @param executor 需要关闭的线程池
- */
- private void shutdownExecutorGracefully(ExecutorService executor) {
- if (executor == null || executor.isTerminated()) return;
- try { executor.shutdown(); if (!executor.awaitTermination(5, TimeUnit.SECONDS)) executor.shutdownNow(); }
- catch (InterruptedException e) { Thread.currentThread().interrupt(); executor.shutdownNow(); }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
deleted file mode 100644
index 8e500a0..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
+++ /dev/null
@@ -1,395 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import io.gate.gateapi.ApiClient;
-import io.gate.gateapi.api.FuturesApi;
-import io.gate.gateapi.models.FuturesInitialOrder;
-import io.gate.gateapi.models.FuturesOrder;
-import io.gate.gateapi.models.FuturesPriceTrigger;
-import io.gate.gateapi.models.FuturesPriceTriggeredOrder;
-import io.gate.gateapi.models.TriggerOrderResponse;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-/**
- * Gate REST API 异步执行器,所有下单/撤单操作经此类提交。
- *
- * <h3>设计目的</h3>
- * REST API 调用可能耗时数百毫秒,若在 WebSocket 回调线程中同步执行会阻塞消息处理,
- * 导致心跳超时误判。本类将所有网络 I/O 提交到独立单线程池异步执行。
- *
- * <h3>线程模型</h3>
- * <ul>
- * <li><b>单线程 + 有界队列(64)</b> — 保证下单顺序,避免并发竞争</li>
- * <li><b>CallerRunsPolicy</b> — 队列满时由提交线程直接执行,形成自然背压</li>
- * <li><b>Daemon 线程</b> — 60s 空闲自动回收</li>
- * </ul>
- *
- * <h3>对外接口</h3>
- * <table>
- * <tr><th>方法</th><th>用途</th><th>调用方</th></tr>
- * <tr><td>openLong / openShort</td><td>市价 IOC 基底开仓</td><td>onKline(WAITING_KLINE)</td></tr>
- * <tr><td>placeConditionalEntryOrder</td><td>挂条件开仓单(价格触发后市价开仓)</td><td>tryGenerateQueues / processShortGrid / processLongGrid</td></tr>
- * <tr><td>placeTakeProfit</td><td>挂止盈条件单(plan-close-*-position)</td><td>tryGenerateQueues / onOrderUpdate / onAutoOrder</td></tr>
- * <tr><td>cancelOrder</td><td>取消限价单(仓位线调整用)</td><td>onPositionUpdate</td></tr>
- * <tr><td>cancelConditionalOrder</td><td>取消单个条件单</td><td>遗留保留</td></tr>
- * <tr><td>cancelAllPriceTriggeredOrders</td><td>取消所有条件单(策略停止时)</td><td>stopGrid</td></tr>
- * </table>
- *
- * <h3>容错</h3>
- * <ul>
- * <li>止盈单创建失败 → 立即 marketClose() 市价平仓</li>
- * <li>取消订单失败 → 仅 warn 日志(可能已成交/已取消)</li>
- * </ul>
- *
- * @author Administrator
- */
-@Slf4j
-public class GateTradeExecutor {
-
- private static final String SETTLE = "usdt";
-
- /** Gate U 本位合约 REST API */
- private final FuturesApi futuresApi;
- /** 合约名称(如 ETH_USDT) */
- private final String contract;
-
- /** 交易线程池:单线程 + 有界队列 + 背压策略 */
- private final ExecutorService executor;
-
- public GateTradeExecutor(ApiClient apiClient, String contract) {
- this.futuresApi = new FuturesApi(apiClient);
- this.contract = contract;
- this.executor = new ThreadPoolExecutor(
- 1, 1,
- 60L, TimeUnit.SECONDS,
- new LinkedBlockingQueue<>(64),
- r -> {
- Thread t = new Thread(r, "gate-trade-worker");
- t.setDaemon(true);
- return t;
- },
- new ThreadPoolExecutor.CallerRunsPolicy()
- );
- ((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true);
- }
-
- /**
- * 优雅关闭:等待 10 秒让队列中的任务执行完毕,超时则强制中断。
- * 关闭后的 REST 调用将通过 CallerRunsPolicy 直接在提交线程执行。
- */
- public void shutdown() {
- executor.shutdown();
- try {
- executor.awaitTermination(10, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- executor.shutdownNow();
- }
- }
-
- /**
- * 异步 IOC 市价开多。quantity 为正数(如 "1")。
- *
- * @param quantity 开仓张数(正数)
- * @param onSuccess 成交成功回调(可为 null)
- * @param onFailure 成交失败回调(可为 null)
- */
- public void openLong(String quantity, Consumer<String> onSuccess, Runnable onFailure) {
- openPosition(quantity, "t-grid-long", "开多", onSuccess, onFailure);
- }
-
- /**
- * 异步 IOC 市价开空。quantity 为负数(如 "-1")。
- *
- * @param quantity 开仓张数(负数)
- * @param onSuccess 成交成功回调(可为 null)
- * @param onFailure 成交失败回调(可为 null)
- */
- public void openShort(String quantity, Consumer<String> onSuccess, Runnable onFailure) {
- openPosition(quantity, "t-grid-short", "开空", onSuccess, onFailure);
- }
-
- /**
- * 通用异步 IOC 市价下单。
- *
- * @param size 下单张数(正=开多 / 负=开空)
- * @param text 订单标记文本(如 "t-grid-long"),用于区分订单来源
- * @param label 日志标签(如 "开多"/"开空")
- * @param onSuccess 成功回调
- * @param onFailure 失败回调
- */
- private void openPosition(String size, String text, String label, Consumer<String> onSuccess, Runnable onFailure) {
- executor.execute(() -> {
- try {
- FuturesOrder order = new FuturesOrder();
- order.setContract(contract);
- order.setSize(size);
- order.setPrice("0");
- order.setTif(FuturesOrder.TifEnum.IOC);
- order.setText(text);
- FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null);
- log.info("[TradeExec] {}成功, 价格:{}, id:{}", label, result.getFillPrice(), result.getId());
- String orderId = String.valueOf(result.getId());
- if (onSuccess != null) {
- onSuccess.accept(orderId);
- }
- } catch (Exception e) {
- log.error("[TradeExec] {}失败", label, e);
- if (onFailure != null) {
- onFailure.run();
- }
- }
- });
- }
-
- /**
- * 异步创建止盈条件单(仓位计划止盈止损)。
- *
- * <p>使用 Gate 的 {@code PriceTriggeredOrder} API:服务器监控价格,达到触发价后自动平指定张数。
- * order_type 使用 {@code plan-close-*-position}(仓位计划止盈止损),
- * 支持指定 size 部分平仓,多次触发的止盈单互不影响。
- *
- * <h3>为何不用 close-*-position</h3>
- * {@code close-long-position} / {@code close-short-position} 仅支持全部平仓(size=0),
- * 且双仓模式还需额外设置 {@code auto_size}。网格策略需要指定张数部分平仓,
- * 因此必须使用 {@code plan-close-long-position} / {@code plan-close-short-position}。
- *
- * @param triggerPrice 触发价格
- * @param rule 触发规则(NUMBER_1: ≥ 触发价,NUMBER_2: ≤ 触发价)
- * @param orderType stop 类型(plan-close-long-position / plan-close-short-position)
- * @param size 平仓张数(正=平空,负=平多)
- */
- public void placeTakeProfit(BigDecimal triggerPrice,
- FuturesPriceTrigger.RuleEnum rule,
- String orderType,
- String size,
- Consumer<String> onSuccess) {
- executor.execute(() -> {
- FuturesPriceTriggeredOrder order = buildTriggeredOrder(triggerPrice, rule, orderType, size);
- try {
- TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order);
- log.info("[TradeExec] 止盈单已创建, 触发价:{}, 类型:{}, size:{}, id:{},idstr:{}",
- triggerPrice, orderType, size, response.getId(), response.getIdString());
- String orderId = String.valueOf(response.getId());
- if (onSuccess != null) {
- onSuccess.accept(orderId);
- }
- } catch (Exception e) {
- log.error("[TradeExec] 止盈单创建失败, 触发价:{}, size:{}, 立即市价止盈", triggerPrice, size, e);
- marketClose(size);
- }
- });
- }
-
- /**
- * 市价止盈:在止盈条件单创建失败时立即市价平仓。
- * size 与止盈单保持一致(负=平多,正=平空)。
- */
- private void marketClose(String size) {
- try {
- FuturesOrder order = new FuturesOrder();
- order.setContract(contract);
- order.setSize(size);
- order.setPrice("0");
- order.setTif(FuturesOrder.TifEnum.IOC);
- order.setReduceOnly(true);
- order.setText("t-grid-mkt-close");
- FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null);
- log.info("[TradeExec] 市价止盈成功, 价格:{}, size:{}, id:{}", result.getFillPrice(), size, result.getId());
- } catch (Exception e) {
- log.error("[TradeExec] 市价止盈也失败, size:{}", size, e);
- }
- }
-
- /**
- * 异步清除指定合约的所有止盈止损条件单。
- */
- public void cancelAllPriceTriggeredOrders() {
- executor.execute(() -> {
- try {
- futuresApi.cancelPriceTriggeredOrderList(SETTLE, contract);
- log.info("[TradeExec] 已清除所有止盈止损条件单");
- } catch (Exception e) {
- log.error("[TradeExec] 清除止盈止损条件单失败", e);
- }
- });
- }
-
- /**
- * <b>遗留方法 — 当前条件单策略未使用</b>
- *
- * <p>异步挂限价单(GTC),用于旧版网格限价开仓。当前策略改用
- * {@link #placeConditionalEntryOrder(BigDecimal, FuturesPriceTrigger.RuleEnum, String, Consumer, Runnable)}。
- *
- * @param price 限价价格
- * @param size 下单张数(正=多 / 负=空)
- * @param onSuccess 成功回调,接收 orderId(可为 null)
- * @param onFailure 失败回调(可为 null)
- */
- public void placeGridLimitOrder(BigDecimal price, String size, Consumer<String> onSuccess, Runnable onFailure) {
- executor.execute(() -> {
- try {
- FuturesOrder order = new FuturesOrder();
- order.setContract(contract);
- order.setSize(size);
- order.setPrice(price.toString());
- order.setTif(FuturesOrder.TifEnum.GTC);
- order.setText(size.startsWith("-") ? "t-grid-limit-short" : "t-grid-limit-long");
- FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null);
- log.info("[TradeExec] 限价单已挂, price:{}, size:{}, id:{}, status:{}", price, size, result.getId(), result.getStatus());
- if (onSuccess != null) {
- onSuccess.accept(String.valueOf(result.getId()));
- }
- } catch (Exception e) {
- log.error("[TradeExec] 限价单挂单失败, price:{}, size:{}", price, size, e);
- if (onFailure != null) {
- onFailure.run();
- }
- }
- });
- }
-
- /**
- * <b>遗留方法 — 当前条件单策略未使用</b>
- *
- * <p>异步取消指定限价单。当前策略改用 {@link #cancelConditionalOrder(String)}。
- *
- * @param orderId 订单 ID,为 null 时跳过
- */
- public void cancelOrder(String orderId,Consumer<String> onSuccess) {
- if (orderId == null) {
- return;
- }
- executor.execute(() -> {
- try {
- FuturesOrder cancelled = futuresApi.cancelFuturesOrder(SETTLE, orderId, null);
- log.info("[TradeExec] 订单已取消, id:{}, status:{}", orderId, cancelled.getStatus());
- if (onSuccess != null) {
- onSuccess.accept(orderId);
- }
- } catch (Exception e) {
- log.warn("[TradeExec] 取消订单失败(可能已成交), id:{}", orderId);
- }
- });
- }
-
- /**
- * 异步创建条件开仓单(价格触发后市价开仓)。
- *
- * <p>服务器监控价格,达到触发价后以市价 IOC 开仓。与止盈单不同,不设 order_type(默认开仓),
- * reduce_only=false。
- *
- * @param triggerPrice 触发价格
- * @param rule 触发规则(NUMBER_1: 最新价≥触发价时执行;NUMBER_2: 最新价≤触发价时执行)
- * @param size 开仓张数(正=开多,负=开空)
- * @param onSuccess 成功回调,接收 conditionOrderId
- * @param onFailure 失败回调
- */
- public void placeConditionalEntryOrder(BigDecimal triggerPrice,
- FuturesPriceTrigger.RuleEnum rule,
- String size,
- Consumer<String> onSuccess,
- Runnable onFailure) {
- executor.execute(() -> {
- try {
- FuturesPriceTrigger trigger = new FuturesPriceTrigger();
- trigger.setStrategyType(FuturesPriceTrigger.StrategyTypeEnum.NUMBER_0);
- trigger.setPriceType(FuturesPriceTrigger.PriceTypeEnum.NUMBER_0);
- trigger.setPrice(triggerPrice.toString());
- trigger.setRule(rule);
- trigger.setExpiration(0);
-
- FuturesInitialOrder initial = new FuturesInitialOrder();
- initial.setContract(contract);
- initial.setSize(Long.parseLong(size));
- initial.setPrice("0");
- initial.setTif(FuturesInitialOrder.TifEnum.IOC);
- initial.setReduceOnly(false);
-
- FuturesPriceTriggeredOrder order = new FuturesPriceTriggeredOrder();
- order.setTrigger(trigger);
- order.setInitial(initial);
-
- TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order);
- String orderId = String.valueOf(response.getId());
- String orderIdStr = response.getIdString();
- log.info("[TradeExec] 条件开仓单已创建, trigger:{}, rule:{}, size:{}, id:{},idStr:{}",
- triggerPrice, rule, size, orderId, orderIdStr);
- if (onSuccess != null) {
- onSuccess.accept(orderId);
- }
- } catch (Exception e) {
- log.error("[TradeExec] 条件开仓单创建失败, trigger:{}, size:{}", triggerPrice, size, e);
- if (onFailure != null) {
- onFailure.run();
- }
- }
- });
- }
-
- /**
- * 异步取消单个条件单。
- *
- * @param orderId 条件单 ID,为 null 时跳过
- */
- public void cancelConditionalOrder(String orderId,Consumer<String> onSuccess) {
- if (orderId == null) {
- return;
- }
- executor.execute(() -> {
- try {
- futuresApi.cancelPriceTriggeredOrder(SETTLE, Long.parseLong(orderId));
- log.info("[TradeExec] 条件单已取消, id:{}", orderId);
- if (onSuccess != null) {
- onSuccess.accept(orderId);
- }
- } catch (Exception e) {
- log.warn("[TradeExec] 取消条件单失败(可能已触发), id:{}", orderId);
- }
- });
- }
-
- /**
- * 构建 FuturesPriceTriggeredOrder 对象。
- *
- * <p>策略=0(价格触发),price_type=0(最新价),expiration=0(永不过期),
- * tif=IOC(立即成交或取消),reduce_only=true(只减仓不开新仓)。
- *
- * <h3>size 参数说明</h3>
- * <ul>
- * <li>plan-close-long-position:size 为负,表示平多仓多少张</li>
- * <li>plan-close-short-position:size 为正,表示平空仓多少张</li>
- * </ul>
- * 每次只平指定张数,不会全平仓位,多个止盈单可并存且互不影响。
- */
- private FuturesPriceTriggeredOrder buildTriggeredOrder(BigDecimal triggerPrice,
- FuturesPriceTrigger.RuleEnum rule,
- String orderType,
- String size) {
- FuturesPriceTrigger trigger = new FuturesPriceTrigger();
- trigger.setStrategyType(FuturesPriceTrigger.StrategyTypeEnum.NUMBER_0);
- trigger.setPriceType(FuturesPriceTrigger.PriceTypeEnum.NUMBER_0);
- trigger.setPrice(triggerPrice.toString());
- trigger.setRule(rule);
- trigger.setExpiration(0);
-
- FuturesInitialOrder initial = new FuturesInitialOrder();
- initial.setContract(contract);
- initial.setSize(Long.parseLong(size));
- initial.setPrice("0");
- initial.setTif(FuturesInitialOrder.TifEnum.IOC);
- initial.setReduceOnly(true);
-
- FuturesPriceTriggeredOrder order = new FuturesPriceTriggeredOrder();
- order.setTrigger(trigger);
- order.setInitial(initial);
- order.setOrderType(orderType);
- return order;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientMain.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientMain.java
deleted file mode 100644
index 6725789..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientMain.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * Gate 网格交易的独立测试入口(main 方法)。
- * 通过 Spring XML 上下文初始化管理器,运行一段时间后手动关闭。
- *
- * @author Administrator
- */
-public class GateWebSocketClientMain {
- /**
- * 独立启动入口:加载 Spring 上下文 → 获取管理器 Bean → 长时间运行 → 销毁。
- *
- * @param args 命令行参数(未使用)
- */
- public static void main(String[] args) throws InterruptedException {
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- GateWebSocketClientManager manager = context.getBean(GateWebSocketClientManager.class);
-
- Thread.sleep(1200000000L);
-
- manager.destroy();
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
deleted file mode 100644
index 7169fe5..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.AutoOrdersChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.CandlestickChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.OrdersChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionClosesChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionsChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.UserTradesChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.math.BigDecimal;
-
-/**
- * Gate 模块 Spring 容器入口 — 组件组装 + 生命周期管理。
- *
- * <h3>组装顺序({@code @PostConstruct})</h3>
- * <ol>
- * <li>{@link GateConfig} — 构建配置(API 密钥、合约、策略参数)</li>
- * <li>{@link GateGridTradeService} — init():获取用户 ID → 切双向持仓 → 清旧条件单 → 平仓 → 设杠杆</li>
- * <li>{@link GateKlineWebSocketClient} — 注册 6 个频道处理器 → init():建立 WS 连接并订阅</li>
- * <li>{@code gridTradeService.startGrid()} — 状态重置,等待首根 K 线</li>
- * </ol>
- *
- * <h3>6 个频道处理器</h3>
- * <ol>
- * <li>CandlestickChannelHandler — 公开频道,K线 → onKline()</li>
- * <li>PositionsChannelHandler — 私有频道,仓位 → onPositionUpdate()</li>
- * <li>PositionClosesChannelHandler — 私有频道,平仓 → onPositionClose()</li>
- * <li>OrdersChannelHandler — 私有频道,订单成交 → onOrderUpdate()</li>
- * <li>UserTradesChannelHandler — 私有频道,用户成交 → onUserTrade()</li>
- * <li>AutoOrdersChannelHandler — 私有频道,条件单状态 → onAutoOrder()</li>
- * </ol>
- *
- * <h3>销毁顺序({@code @PreDestroy})</h3>
- * <ol>
- * <li>gridTradeService.stopGrid():取消所有条件单 → 关闭交易线程池</li>
- * <li>wsClient.destroy():取消订阅 → 断开 WS → 关闭线程池</li>
- * </ol>
- *
- * @author Administrator
- */
-@Slf4j
-@Component
-public class GateWebSocketClientManager {
-
- /** WebSocket 连接管理器 */
- private GateKlineWebSocketClient wsClient;
- /** 网格交易策略服务 */
- private GateGridTradeService gridTradeService;
- /** 统一配置 */
- private GateConfig config;
-
- @PostConstruct
- public void init() {
- log.info("[管理器] 开始初始化...");
-
- try {
- //实盘
- config = GateConfig.builder()
- .apiKey("a2338398e00b7935104520e16be96918")
- .apiSecret("9111d897f2346d5217619f2da76536632715fef4d7eb304c6c61e869a2a74e98")
- .contract("ETH_USDT")
- .leverage("100")
- .marginMode("CROSS")
- .positionMode("dual")
- .gridRate(new BigDecimal("0.0025"))
- .expectedProfit(new BigDecimal("2"))
- .maxLoss(new BigDecimal("15"))
- .quantity("1")
- .priceScale(2)
- .contractMultiplier(new BigDecimal("0.01"))
- .unrealizedPnlPriceMode(GateConfig.PnLPriceMode.LAST_PRICE)
- .isProduction(true)
- .reopenMaxRetries(3)
- .build();
-// //测试盘
-// config = GateConfig.builder()
-// .apiKey("d90ca272391992b8e74f8f92cedb21ec")
-// .apiSecret("1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274")
-// .contract("ETH_USDT")
-// .leverage("100")
-// .marginMode("CROSS")
-// .positionMode("dual")
-// .gridRate(new BigDecimal("0.002"))
-// .expectedProfit(new BigDecimal("1"))
-// .maxLoss(new BigDecimal("15"))
-// .quantity("1")
-// .priceScale(1)
-// .contractMultiplier(new BigDecimal("0.01"))
-// .unrealizedPnlPriceMode(GateConfig.PnLPriceMode.LAST_PRICE)
-// .isProduction(false)
-// .reopenMaxRetries(3)
-// .build();
-
- // 1. 初始化交易服务:查用户ID → 切持仓模式 → 清条件单 → 平已有仓位 → 设杠杆
- gridTradeService = new GateGridTradeService(config);
- gridTradeService.init();
-
- // 2. 创建 WS 客户端并注册 3 个频道处理器
- wsClient = new GateKlineWebSocketClient(config.getWsUrl());
- wsClient.addChannelHandler(new CandlestickChannelHandler(config.getContract(), gridTradeService));
- wsClient.addChannelHandler(new PositionsChannelHandler(
- config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
- wsClient.addChannelHandler(new PositionClosesChannelHandler(
- config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
- wsClient.addChannelHandler(new OrdersChannelHandler(
- config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
- wsClient.addChannelHandler(new UserTradesChannelHandler(
- config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
- wsClient.addChannelHandler(new AutoOrdersChannelHandler(
- config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
- wsClient.init();
- log.info("[管理器] WS已连接, 已注册 6 个频道处理器");
-
- // 3. 激活策略,等待首根 K 线触发基底双开
- gridTradeService.startGrid();
- } catch (Exception e) {
- log.error("[管理器] 初始化失败", e);
- }
- }
-
- /**
- * 销毁:停止策略 → 关闭交易线程池 → 取消 WS 订阅 → 断开连接 → 关闭 WS 线程池。
- */
- @PreDestroy
- public void destroy() {
- log.info("[管理器] 开始销毁...");
- if (gridTradeService != null) {
- gridTradeService.stopGrid();
- }
- if (wsClient != null) {
- wsClient.destroy();
- }
- log.info("[管理器] 销毁完成");
- }
-
- /**
- * @return WebSocket 连接管理器实例
- */
- public GateKlineWebSocketClient getKlineWebSocketClient() { return wsClient; }
- /**
- * @return 网格交易策略服务实例
- */
- public GateGridTradeService getGridTradeService() { return gridTradeService; }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java b/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
deleted file mode 100644
index 8601f69..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
+++ /dev/null
@@ -1,532 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 网格价格层级,策略的最小操作单元。
- *
- * <h3>定位</h3>
- * 每个 GridElement 对应网格中的一个价格点,同时持有该点的多仓和空仓挂单状态。
- * 与传统的"价格队列+Map"模式不同,GridElement 将价格、方向、状态、订单ID 聚合到一个对象中,
- * 并维护全局静态 HashMap 索引实现 O(1) 双向查询。
- *
- * <h3>ID 体系与链表</h3>
- * <pre>
- * ID ≦ -1: 空仓队列区域(降序),ID 自减,gridPrice 递减
- * ID = 0: 基座位置,gridPrice = shortBaseEntryPrice
- * ID ≧ 1: 多仓队列区域(升序),ID 自增,gridPrice 递增
- *
- * 链表: ... ← -3 ← -2 ← -1 ← 0 → 1 → 2 → 3 → ...
- * (通过 upId/downId + INDEX 实现 O(1) 遍历)
- * </pre>
- *
- * <h3>字段分组</h3>
- * <table>
- * <tr><th>类别</th><th>字段</th><th>说明</th></tr>
- * <tr><td>标识</td><td>id, gridPrice, upId, downId</td><td>编号、价格、双向链表指针</td></tr>
- * <tr><td>多仓订单</td><td>hasLongOrder, longOrderId, longTraderParam</td><td>是否有挂单、订单ID、完整参数</td></tr>
- * <tr><td>空仓订单</td><td>hasShortOrder, shortOrderId, shortTraderParam</td><td>是否有挂单、订单ID、完整参数</td></tr>
- * <tr><td>止盈</td><td>longTakeProfitOrderId, shortTakeProfitOrderId</td><td>止盈条件单ID</td></tr>
- * </table>
- *
- * <h3>6 个全局 O(1) 索引</h3>
- * <pre>
- * INDEX → findById(int) ID → 元素
- * PRICE_INDEX → findByPrice(BigDecimal) 价格 → 元素
- * LONG_ORDER_ID_INDEX → findByLongOrderId(String) 多仓挂单ID → 元素
- * SHORT_ORDER_ID_INDEX → findByShortOrderId(String) 空仓挂单ID → 元素
- * LONG_TP_ORDER_ID_INDEX→ findByLongTakeProfitOrderId(String) 多止盈ID → 元素
- * SHORT_TP_ORDER_ID_INDEX→ findByShortTakeProfitOrderId(String) 空止盈ID → 元素
- * </pre>
- * 索引通过 {@link #rebuildIndex(List)}(全量重建)或 {@link #refreshIndices()}(增量刷新)
- * 维护,每次操作后自动打印全量网格状态到控制台。
- *
- * <h3>何时填充 TraderParam</h3>
- * 初始化时 {@code updateGridElements()} 为每个元素预填充 longTraderParam 和 shortTraderParam
- * (含 direction/entryPrice/takeProfitPrice/quantity),订单ID字段在挂单成功后由
- * {@link GateGridTradeService} 的 4 个辅助方法写入。
- *
- * <h3>使用示例</h3>
- * <pre>
- * GridElement elem = GridElement.findById(1);
- * boolean hasLong = elem.isHasLongOrder(); // 是否挂了多单
- * BigDecimal tpPrice = elem.getLongTraderParam().getTakeProfitPrice(); // 止盈价
- * elem.getUp(); // 上一个网格(O(1))
- * elem.getDown(); // 下一个网格(O(1))
- * </pre>
- *
- * @author Administrator
- */
-public class GridElement {
-
- /** 网格层级编号 */
- private int id;
- /** 网格触发价格 */
- private BigDecimal gridPrice;
- /** 是否存在多仓挂单 */
- private boolean hasLongOrder;
- /** 是否存在空仓挂单 */
- private boolean hasShortOrder;
- /** 多仓挂单参数 */
- private TraderParam longTraderParam;
- /** 空仓挂单参数 */
- private TraderParam shortTraderParam;
- /** 上一个网格编号,null 表示无上一级 */
- private Integer upId;
- /** 下一个网格编号,null 表示无下一级 */
- private Integer downId;
- /** 多仓挂单订单 ID */
- private String longOrderId;
- /** 空仓挂单订单 ID */
- private String shortOrderId;
- /** 多仓止盈订单 ID */
- private String longTakeProfitOrderId;
- /** 空仓止盈订单 ID */
- private String shortTakeProfitOrderId;
- /** 多仓止损订单 ID */
- private String longStopLossOrderId;
- /** 空仓止损订单 ID */
- private String shortStopLossOrderId;
-
- /** 全局 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
- private static final Map<Integer, GridElement> INDEX = new ConcurrentHashMap<>();
- /** 全局价格索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
- private static final Map<BigDecimal, GridElement> PRICE_INDEX = new ConcurrentHashMap<>();
- /** 全局多仓订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
- private static final Map<String, GridElement> LONG_ORDER_ID_INDEX = new ConcurrentHashMap<>();
- /** 全局空仓订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
- private static final Map<String, GridElement> SHORT_ORDER_ID_INDEX = new ConcurrentHashMap<>();
- /** 全局多仓止盈订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
- private static final Map<String, GridElement> LONG_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
- /** 全局空仓止盈订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
- private static final Map<String, GridElement> SHORT_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
- /** 全局多仓止损订单 ID 索引 */
- private static final Map<String, GridElement> LONG_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>();
- /** 全局空仓止损订单 ID 索引 */
- private static final Map<String, GridElement> SHORT_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>();
-
- /**
- * 根据 ID 快速查找网格元素(O(1))。
- *
- * @param id 网格层级编号
- * @return 对应的 GridElement,不存在则返回 null
- */
- public static GridElement findById(int id) {
- return INDEX.get(id);
- }
-
- /**
- * 根据价格快速查找网格元素(O(1))。
- *
- * @param price 网格价格
- * @return 对应的 GridElement,不存在则返回 null
- */
- public static GridElement findByPrice(BigDecimal price) {
- return PRICE_INDEX.get(price);
- }
-
- /**
- * 根据多仓挂单订单 ID 快速查找网格元素(O(1))。
- *
- * @param orderId 多仓挂单订单 ID
- * @return 对应的 GridElement,不存在则返回 null
- */
- public static GridElement findByLongOrderId(String orderId) {
- return LONG_ORDER_ID_INDEX.get(orderId);
- }
-
- /**
- * 根据空仓挂单订单 ID 快速查找网格元素(O(1))。
- *
- * @param orderId 空仓挂单订单 ID
- * @return 对应的 GridElement,不存在则返回 null
- */
- public static GridElement findByShortOrderId(String orderId) {
- return SHORT_ORDER_ID_INDEX.get(orderId);
- }
-
- /**
- * 根据多仓止盈订单 ID 快速查找网格元素(O(1))。
- *
- * @param orderId 多仓止盈订单 ID
- * @return 对应的 GridElement,不存在则返回 null
- */
- public static GridElement findByLongTakeProfitOrderId(String orderId) {
- return LONG_TP_ORDER_ID_INDEX.get(orderId);
- }
-
- /**
- * 根据空仓止盈订单 ID 快速查找网格元素(O(1))。
- *
- * @param orderId 空仓止盈订单 ID
- * @return 对应的 GridElement,不存在则返回 null
- */
- public static GridElement findByShortTakeProfitOrderId(String orderId) {
- return SHORT_TP_ORDER_ID_INDEX.get(orderId);
- }
-
- /**
- * 根据多仓止损订单 ID 快速查找网格元素(O(1))。
- */
- public static GridElement findByLongStopLossOrderId(String orderId) {
- return LONG_SL_ORDER_ID_INDEX.get(orderId);
- }
-
- /**
- * 根据空仓止损订单 ID 快速查找网格元素(O(1))。
- */
- public static GridElement findByShortStopLossOrderId(String orderId) {
- return SHORT_SL_ORDER_ID_INDEX.get(orderId);
- }
-
- /**
- * 从列表中重建全局 ID 索引和价格索引。
- * 由 {@link GateConfig#setGridElements(List)} 在每次列表变更后调用。
- */
- public static void rebuildIndex(List<GridElement> elements) {
- INDEX.clear();
- PRICE_INDEX.clear();
- LONG_ORDER_ID_INDEX.clear();
- SHORT_ORDER_ID_INDEX.clear();
- LONG_TP_ORDER_ID_INDEX.clear();
- SHORT_TP_ORDER_ID_INDEX.clear();
- LONG_SL_ORDER_ID_INDEX.clear();
- SHORT_SL_ORDER_ID_INDEX.clear();
- for (GridElement e : elements) {
- INDEX.put(e.getId(), e);
- putDynamicIndices(e);
- }
- logAll();
- }
-
- /**
- * 刷新动态索引(价格索引、多仓/空仓订单 ID 索引)。
- * 在对 GridElement 的 {@link #longOrderId}、{@link #shortOrderId}、
- * {@link #longTraderParam}、{@link #shortTraderParam} 等字段修改后调用,
- * 使快速查找方法获取到最新数据。
- */
- public static void refreshIndices() {
- PRICE_INDEX.clear();
- LONG_ORDER_ID_INDEX.clear();
- SHORT_ORDER_ID_INDEX.clear();
- LONG_TP_ORDER_ID_INDEX.clear();
- SHORT_TP_ORDER_ID_INDEX.clear();
- LONG_SL_ORDER_ID_INDEX.clear();
- SHORT_SL_ORDER_ID_INDEX.clear();
- for (GridElement e : INDEX.values()) {
- putDynamicIndices(e);
- }
- logAll();
- }
-
- /**
- * 打印全部网格数据到日志。
- */
- public static void logAll() {
- List<GridElement> sorted = new ArrayList<>(INDEX.values());
- sorted.sort((a, b) -> Integer.compare(a.getId(), b.getId()));
- StringBuilder sb = new StringBuilder("\n========== 网格数据 ==========\n");
- for (GridElement e : sorted) {
- if (e.isHasLongOrder() || e.isHasShortOrder()
- || e.getLongStopLossOrderId() != null || e.getShortStopLossOrderId() != null){
- sb.append(String.format(
- " ID=%4d 价格=%s up=%s down=%s 多仓=%s(%s) 空仓=%s(%s) 多止盈=%s 空止盈=%s 多止损=%s 空止损=%s\n",
- e.getId(),
- e.getGridPrice(),
- e.getUpId(),
- e.getDownId(),
- e.isHasLongOrder() ? "有" : "无",
- e.getLongOrderId() != null ? e.getLongOrderId() : "-",
- e.isHasShortOrder() ? "有" : "无",
- e.getShortOrderId() != null ? e.getShortOrderId() : "-",
- e.getLongTakeProfitOrderId() != null ? e.getLongTakeProfitOrderId() : "-",
- e.getShortTakeProfitOrderId() != null ? e.getShortTakeProfitOrderId() : "-",
- e.getLongStopLossOrderId() != null ? e.getLongStopLossOrderId() : "-",
- e.getShortStopLossOrderId() != null ? e.getShortStopLossOrderId() : "-"
- ));
- }
- }
- sb.append(String.format(
- "------------------------------------------------------------\n" +
- " 索引统计: ID=%d 价格=%d 多仓订单ID=%d 空仓订单ID=%d 多止盈ID=%d 空止盈ID=%d 多止损ID=%d 空止损ID=%d\n",
- INDEX.size(),
- PRICE_INDEX.size(),
- LONG_ORDER_ID_INDEX.size(),
- SHORT_ORDER_ID_INDEX.size(),
- LONG_TP_ORDER_ID_INDEX.size(),
- SHORT_TP_ORDER_ID_INDEX.size(),
- LONG_SL_ORDER_ID_INDEX.size(),
- SHORT_SL_ORDER_ID_INDEX.size()
- ));
- sb.append(String.format(" 多仓订单ID索引: %s\n", LONG_ORDER_ID_INDEX.keySet()));
- sb.append(String.format(" 空仓订单ID索引: %s\n", SHORT_ORDER_ID_INDEX.keySet()));
- sb.append(String.format(" 多止盈ID索引: %s\n", LONG_TP_ORDER_ID_INDEX.keySet()));
- sb.append(String.format(" 空止盈ID索引: %s\n", SHORT_TP_ORDER_ID_INDEX.keySet()));
- sb.append("================================\n");
- System.out.println(sb);
- }
-
- /**
- * 获取所有已挂多仓条件单的网格元素。
- * 小于空仓仓位线的多单
- *
- * @return 已挂多仓条件单的 GridElement 列表
- */
- public static List<GridElement> findAllShortOrders(BigDecimal currentPrice) {
- List<GridElement> result = new ArrayList<>();
- for (GridElement e : INDEX.values()) {
- if (e.isHasShortOrder() && e.getGridPrice().compareTo(currentPrice) < 0 && e.getShortTakeProfitOrderId() == null) {
- result.add(e);
- }
- }
- return result;
- }
-
- /**
- * 获取所有已挂空仓条件单的网格元素。
- * 大于多仓仓位线的空单
- *
- * @return 已挂空仓条件单的 GridElement 列表
- */
- public static List<GridElement> findAllLongOrders(BigDecimal currentPrice) {
- List<GridElement> result = new ArrayList<>();
- for (GridElement e : INDEX.values()) {
- if (e.isHasLongOrder() && e.getGridPrice().compareTo(currentPrice) > 0 && e.getLongTakeProfitOrderId() == null) {
- result.add(e);
- }
- }
- return result;
- }
-
- private static void putDynamicIndices(GridElement e) {
- PRICE_INDEX.put(e.getGridPrice(), e);
- if (e.getLongOrderId() != null) {
- LONG_ORDER_ID_INDEX.put(e.getLongOrderId(), e);
- }
- if (e.getShortOrderId() != null) {
- SHORT_ORDER_ID_INDEX.put(e.getShortOrderId(), e);
- }
- if (e.getLongTakeProfitOrderId() != null) {
- LONG_TP_ORDER_ID_INDEX.put(e.getLongTakeProfitOrderId(), e);
- }
- if (e.getShortTakeProfitOrderId() != null) {
- SHORT_TP_ORDER_ID_INDEX.put(e.getShortTakeProfitOrderId(), e);
- }
- if (e.getLongStopLossOrderId() != null) {
- LONG_SL_ORDER_ID_INDEX.put(e.getLongStopLossOrderId(), e);
- }
- if (e.getShortStopLossOrderId() != null) {
- SHORT_SL_ORDER_ID_INDEX.put(e.getShortStopLossOrderId(), e);
- }
- }
-
- /**
- * @return 根据 upId 获取上一个网格元素,无上一级则返回 null
- */
- public GridElement getUp() {
- return upId != null ? INDEX.get(upId) : null;
- }
-
- /**
- * @return 根据 downId 获取下一个网格元素,无下一级则返回 null
- */
- public GridElement getDown() {
- return downId != null ? INDEX.get(downId) : null;
- }
-
- private GridElement(Builder builder) {
- this.id = builder.id;
- this.gridPrice = builder.gridPrice;
- this.hasLongOrder = builder.hasLongOrder;
- this.hasShortOrder = builder.hasShortOrder;
- this.longTraderParam = builder.longTraderParam;
- this.shortTraderParam = builder.shortTraderParam;
- this.upId = builder.upId;
- this.downId = builder.downId;
- this.longOrderId = builder.longOrderId;
- this.shortOrderId = builder.shortOrderId;
- this.longTakeProfitOrderId = builder.longTakeProfitOrderId;
- this.shortTakeProfitOrderId = builder.shortTakeProfitOrderId;
- this.longStopLossOrderId = builder.longStopLossOrderId;
- this.shortStopLossOrderId = builder.shortStopLossOrderId;
- }
-
- // ==================== 网格层级编号 ====================
-
- /** @return 网格层级编号 */
- public int getId() { return id; }
- /** 设置网格层级编号 */
- public void setId(int id) { this.id = id; }
-
- // ==================== 网格价格 ====================
-
- /** @return 网格触发价格 */
- public BigDecimal getGridPrice() { return gridPrice; }
- /** 设置网格触发价格 */
- public void setGridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; }
-
- // ==================== 多仓挂单标记 ====================
-
- /** @return 是否存在多仓挂单 */
- public boolean isHasLongOrder() { return hasLongOrder; }
- /** 标记是否存在多仓挂单 */
- public void setHasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; }
-
- // ==================== 空仓挂单标记 ====================
-
- /** @return 是否存在空仓挂单 */
- public boolean isHasShortOrder() { return hasShortOrder; }
- /** 标记是否存在空仓挂单 */
- public void setHasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; }
-
- // ==================== 多仓挂单参数 ====================
-
- /** @return 多仓挂单参数 */
- public TraderParam getLongTraderParam() { return longTraderParam; }
- /** 设置多仓挂单参数 */
- public void setLongTraderParam(TraderParam longTraderParam) { this.longTraderParam = longTraderParam; }
-
- // ==================== 空仓挂单参数 ====================
-
- /** @return 空仓挂单参数 */
- public TraderParam getShortTraderParam() { return shortTraderParam; }
- /** 设置空仓挂单参数 */
- public void setShortTraderParam(TraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; }
-
- // ==================== 上一个网格编号 ====================
-
- /** @return 上一个网格编号,null 表示无上一级 */
- public Integer getUpId() { return upId; }
- /** 设置上一个网格编号 */
- public void setUpId(Integer upId) { this.upId = upId; }
-
- // ==================== 下一个网格编号 ====================
-
- /** @return 下一个网格编号,null 表示无下一级 */
- public Integer getDownId() { return downId; }
- /** 设置下一个网格编号 */
- public void setDownId(Integer downId) { this.downId = downId; }
-
- // ==================== 多仓挂单订单 ID ====================
-
- /** @return 多仓挂单订单 ID */
- public String getLongOrderId() { return longOrderId; }
- /** 设置多仓挂单订单 ID */
- public void setLongOrderId(String longOrderId) { this.longOrderId = longOrderId; }
-
- // ==================== 空仓挂单订单 ID ====================
-
- /** @return 空仓挂单订单 ID */
- public String getShortOrderId() { return shortOrderId; }
- /** 设置空仓挂单订单 ID */
- public void setShortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; }
-
- // ==================== 多仓止盈订单 ID ====================
-
- /** @return 多仓止盈订单 ID */
- public String getLongTakeProfitOrderId() { return longTakeProfitOrderId; }
- /** 设置多仓止盈订单 ID */
- public void setLongTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; }
-
- // ==================== 空仓止盈订单 ID ====================
-
- /** @return 空仓止盈订单 ID */
- public String getShortTakeProfitOrderId() { return shortTakeProfitOrderId; }
- /** 设置空仓止盈订单 ID */
- public void setShortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; }
-
- // ==================== 多仓止损订单 ID ====================
-
- /** @return 多仓止损订单 ID */
- public String getLongStopLossOrderId() { return longStopLossOrderId; }
- /** 设置多仓止损订单 ID */
- public void setLongStopLossOrderId(String longStopLossOrderId) { this.longStopLossOrderId = longStopLossOrderId; }
-
- // ==================== 空仓止损订单 ID ====================
-
- /** @return 空仓止损订单 ID */
- public String getShortStopLossOrderId() { return shortStopLossOrderId; }
- /** 设置空仓止损订单 ID */
- public void setShortStopLossOrderId(String shortStopLossOrderId) { this.shortStopLossOrderId = shortStopLossOrderId; }
-
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * GridElement 的流式构造器。
- *
- * <h3>必填项</h3>
- * {@code id}、{@code gridPrice} 必须设置。
- *
- * <h3>默认值</h3>
- * hasLongOrder/hasShortOrder 默认为 false,upId/downId/TraderParam 默认为 null
- */
- public static class Builder {
- /** 网格层级编号(必填) */
- private int id;
- /** 网格触发价格(必填) */
- private BigDecimal gridPrice;
- /** 是否有多仓挂单,默认 false */
- private boolean hasLongOrder = false;
- /** 是否有空仓挂单,默认 false */
- private boolean hasShortOrder = false;
- /** 多仓挂单参数 */
- private TraderParam longTraderParam;
- /** 空仓挂单参数 */
- private TraderParam shortTraderParam;
- /** 上一个网格编号,默认 null(无上一级) */
- private Integer upId;
- /** 下一个网格编号,默认 null(无下一级) */
- private Integer downId;
- /** 多仓挂单订单 ID */
- private String longOrderId;
- /** 空仓挂单订单 ID */
- private String shortOrderId;
- /** 多仓止盈订单 ID */
- private String longTakeProfitOrderId;
- /** 空仓止盈订单 ID */
- private String shortTakeProfitOrderId;
- /** 多仓止损订单 ID */
- private String longStopLossOrderId;
- /** 空仓止损订单 ID */
- private String shortStopLossOrderId;
-
- /** 设置网格层级编号 */
- public Builder id(int id) { this.id = id; return this; }
- /** 设置网格触发价格 */
- public Builder gridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; return this; }
- /** 设置是否存在多仓挂单 */
- public Builder hasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; return this; }
- /** 设置是否存在空仓挂单 */
- public Builder hasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; return this; }
- /** 设置多仓挂单参数 */
- public Builder longTraderParam(TraderParam longTraderParam) { this.longTraderParam = longTraderParam; return this; }
- /** 设置空仓挂单参数 */
- public Builder shortTraderParam(TraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; return this; }
- /** 设置上一个网格编号 */
- public Builder upId(Integer upId) { this.upId = upId; return this; }
- /** 设置下一个网格编号 */
- public Builder downId(Integer downId) { this.downId = downId; return this; }
- /** 设置多仓挂单订单 ID */
- public Builder longOrderId(String longOrderId) { this.longOrderId = longOrderId; return this; }
- /** 设置空仓挂单订单 ID */
- public Builder shortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; return this; }
- /** 设置多仓止盈订单 ID */
- public Builder longTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; return this; }
- /** 设置空仓止盈订单 ID */
- public Builder shortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; return this; }
- /** 设置多仓止损订单 ID */
- public Builder longStopLossOrderId(String longStopLossOrderId) { this.longStopLossOrderId = longStopLossOrderId; return this; }
- /** 设置空仓止损订单 ID */
- public Builder shortStopLossOrderId(String shortStopLossOrderId) { this.shortStopLossOrderId = shortStopLossOrderId; return this; }
-
- public GridElement build() {
- return new GridElement(this);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java b/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java
deleted file mode 100644
index 08ba24a..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import java.math.BigDecimal;
-
-/**
- * 单笔挂单的完整参数,封装条件开仓单及止盈单的状态。
- *
- * <h3>定位</h3>
- * 每个 GridElement 内嵌两个 TraderParam(longTraderParam / shortTraderParam),
- * 分别记录该价格层级上多仓和空仓的挂单参数。所有字段通过 getter/setter
- * 在挂单/成交/止盈各阶段逐步填充。
- *
- * <h3>字段分组</h3>
- * <table>
- * <tr><th>类别</th><th>字段</th><th>生命周期</th></tr>
- * <tr><td>开仓准备</td><td>direction, entryPrice, quantity</td><td>updateGridElements() 预填充</td></tr>
- * <tr><td>止盈预定</td><td>takeProfitPrice</td><td>updateGridElements() 预填充(entryPrice ± (step - minTick))</td></tr>
- * <tr><td>挂单确认</td><td>entryOrderPlaced, entryOrderId</td><td>条件单挂成功后由 longEntryTraderIdParam 等写入</td></tr>
- * <tr><td>止盈确认</td><td>takeProfitPlaced, takeProfitOrderId</td><td>止盈单挂成功后由 longTakeProfitTraderIdParam 等写入</td></tr>
- * <tr><td>定位</td><td>entryGridPosition, takeProfitGridPosition</td><td>当前策略中由 upId/downId 替代</td></tr>
- * </table>
- *
- * <h3>盈利公式(正向合约)</h3>
- * <pre>
- * 多仓止盈盈利 = takeProfitPrice - entryPrice = (entryPrice + step - minTick) - entryPrice = step - minTick
- * 空仓止盈盈利 = entryPrice - takeProfitPrice = entryPrice - (entryPrice - step + minTick) = step - minTick
- * </pre>
- *
- * @author Administrator
- */
-public class TraderParam {
-
- /**
- * 交易方向。
- * <ul>
- * <li>{@link #LONG} — 多头</li>
- * <li>{@link #SHORT} — 空头</li>
- * </ul>
- */
- public enum Direction {
- /** 多头方向 */
- LONG,
- /** 空头方向 */
- SHORT
- }
-
- /** 交易方向(多 / 空) */
- private Direction direction;
- /** 下单数量(合约张数) */
- private String quantity;
- /** 挂单价在网格队列中的位置(索引,-1 表示未定位) */
- private int entryGridPosition;
- /** 条件开仓触发价 */
- private BigDecimal entryPrice;
- /** 挂单(条件开仓单)订单 ID */
- private String entryOrderId;
- /** 挂单价(条件开仓单)是否挂成功 */
- private boolean entryOrderPlaced;
- /** 止盈价在网格队列中的位置(索引,-1 表示未定位) */
- private int takeProfitGridPosition;
- /** 止盈触发价 */
- private BigDecimal takeProfitPrice;
- /** 止盈条件单订单 ID */
- private String takeProfitOrderId;
- /** 止盈价是否挂成功 */
- private boolean takeProfitPlaced;
-
- private TraderParam(Builder builder) {
- this.direction = builder.direction;
- this.entryPrice = builder.entryPrice;
- this.takeProfitPrice = builder.takeProfitPrice;
- this.quantity = builder.quantity;
- this.takeProfitPlaced = builder.takeProfitPlaced;
- this.entryOrderPlaced = builder.entryOrderPlaced;
- this.entryGridPosition = builder.entryGridPosition;
- this.takeProfitGridPosition = builder.takeProfitGridPosition;
- this.takeProfitOrderId = builder.takeProfitOrderId;
- this.entryOrderId = builder.entryOrderId;
- }
-
- // ==================== 交易方向 ====================
-
- /** @return 交易方向(多 / 空) */
- public Direction getDirection() { return direction; }
- /** 设置交易方向 */
- public void setDirection(Direction direction) { this.direction = direction; }
-
- // ==================== 条件开仓触发价 ====================
-
- /** @return 条件开仓触发价 */
- public BigDecimal getEntryPrice() { return entryPrice; }
- /** 设置条件开仓触发价 */
- public void setEntryPrice(BigDecimal entryPrice) { this.entryPrice = entryPrice; }
-
- // ==================== 止盈触发价 ====================
-
- /** @return 止盈触发价 */
- public BigDecimal getTakeProfitPrice() { return takeProfitPrice; }
- /** 设置止盈触发价 */
- public void setTakeProfitPrice(BigDecimal takeProfitPrice) { this.takeProfitPrice = takeProfitPrice; }
-
- // ==================== 下单数量 ====================
-
- /** @return 下单数量(合约张数) */
- public String getQuantity() { return quantity; }
- /** 设置下单数量 */
- public void setQuantity(String quantity) { this.quantity = quantity; }
-
- // ==================== 挂单价网格位置 ====================
-
- /** @return 挂单价在网格队列中的索引位置,-1 表示未定位 */
- public int getEntryGridPosition() { return entryGridPosition; }
- /** 设置挂单价在网格队列中的索引位置 */
- public void setEntryGridPosition(int entryGridPosition) { this.entryGridPosition = entryGridPosition; }
-
- // ==================== 止盈价网格位置 ====================
-
- /** @return 止盈价在网格队列中的索引位置,-1 表示未定位 */
- public int getTakeProfitGridPosition() { return takeProfitGridPosition; }
- /** 设置止盈价在网格队列中的索引位置 */
- public void setTakeProfitGridPosition(int takeProfitGridPosition) { this.takeProfitGridPosition = takeProfitGridPosition; }
-
- // ==================== 止盈价是否挂成功 ====================
-
- /** @return 止盈条件单是否已挂成功 */
- public boolean isTakeProfitPlaced() { return takeProfitPlaced; }
- /** 标记止盈条件单已挂成功 */
- public void setTakeProfitPlaced(boolean takeProfitPlaced) { this.takeProfitPlaced = takeProfitPlaced; }
-
- // ==================== 挂单价是否挂成功 ====================
-
- /** @return 条件开仓单是否已挂成功 */
- public boolean isEntryOrderPlaced() { return entryOrderPlaced; }
- /** 标记条件开仓单已挂成功 */
- public void setEntryOrderPlaced(boolean entryOrderPlaced) { this.entryOrderPlaced = entryOrderPlaced; }
-
- // ==================== 止盈订单 ID ====================
-
- /** @return 止盈条件单订单 ID(挂成功后由交易所返回) */
- public String getTakeProfitOrderId() { return takeProfitOrderId; }
- /** 记录止盈条件单订单 ID */
- public void setTakeProfitOrderId(String takeProfitOrderId) { this.takeProfitOrderId = takeProfitOrderId; }
-
- // ==================== 挂单订单 ID ====================
-
- /** @return 挂单(条件开仓单)订单 ID(挂成功后由交易所返回) */
- public String getEntryOrderId() { return entryOrderId; }
- /** 记录条件开仓单订单 ID */
- public void setEntryOrderId(String entryOrderId) { this.entryOrderId = entryOrderId; }
-
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * TraderParam 的流式构造器。
- *
- * <h3>必填项</h3>
- * {@code direction}、{@code entryPrice}、{@code takeProfitPrice} 必须设置。
- *
- * <h3>默认值</h3>
- * quantity=1 / entryGridPosition=-1 / takeProfitGridPosition=-1 / 挂单状态均为 false
- */
- public static class Builder {
- /** 交易方向(必填) */
- private Direction direction;
- /** 条件开仓触发价(必填) */
- private BigDecimal entryPrice;
- /** 止盈触发价(必填) */
- private BigDecimal takeProfitPrice;
- /** 下单数量,默认 "1" */
- private String quantity = "1";
- /** 止盈价是否挂成功,默认 false */
- private boolean takeProfitPlaced = false;
- /** 挂单价是否挂成功,默认 false */
- private boolean entryOrderPlaced = false;
- /** 挂单价网格位置,默认 -1(未定位) */
- private int entryGridPosition = -1;
- /** 止盈价网格位置,默认 -1(未定位) */
- private int takeProfitGridPosition = -1;
- /** 止盈订单 ID */
- private String takeProfitOrderId;
- /** 挂单订单 ID */
- private String entryOrderId;
-
- /** 设置交易方向(多 / 空) */
- public Builder direction(Direction direction) { this.direction = direction; return this; }
- /** 设置条件开仓触发价 */
- public Builder entryPrice(BigDecimal entryPrice) { this.entryPrice = entryPrice; return this; }
- /** 设置止盈触发价 */
- public Builder takeProfitPrice(BigDecimal takeProfitPrice) { this.takeProfitPrice = takeProfitPrice; return this; }
- /** 设置下单数量(合约张数) */
- public Builder quantity(String quantity) { this.quantity = quantity; return this; }
- /** 设置止盈价是否已挂成功 */
- public Builder takeProfitPlaced(boolean takeProfitPlaced) { this.takeProfitPlaced = takeProfitPlaced; return this; }
- /** 设置挂单价是否已挂成功 */
- public Builder entryOrderPlaced(boolean entryOrderPlaced) { this.entryOrderPlaced = entryOrderPlaced; return this; }
- /** 设置挂单价在网格队列中的索引位置 */
- public Builder entryGridPosition(int entryGridPosition) { this.entryGridPosition = entryGridPosition; return this; }
- /** 设置止盈价在网格队列中的索引位置 */
- public Builder takeProfitGridPosition(int takeProfitGridPosition) { this.takeProfitGridPosition = takeProfitGridPosition; return this; }
- /** 设置止盈条件单订单 ID */
- public Builder takeProfitOrderId(String takeProfitOrderId) { this.takeProfitOrderId = takeProfitOrderId; return this; }
- /** 设置挂单(条件开仓单)订单 ID */
- public Builder entryOrderId(String entryOrderId) { this.entryOrderId = entryOrderId; return this; }
-
- public TraderParam build() {
- return new TraderParam(this);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/celue.out b/src/main/java/com/xcong/excoin/modules/gateApi/celue.out
deleted file mode 100644
index 7d06d00..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/celue.out
+++ /dev/null
Binary files differ
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/gate-api.txt b/src/main/java/com/xcong/excoin/modules/gateApi/gate-api.txt
deleted file mode 100644
index f2d8ce7..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/gate-api.txt
+++ /dev/null
@@ -1,3067 +0,0 @@
-访问链接
-REST API BaseURL:
-
-实盘交易: https://api.gateio.ws/api/v4
-模拟交易:https://api-testnet.gateapi.io/api/v4
-合约实盘交易备选入口(只适用合约 API):https://fx-api.gateio.ws/api/v4
-#SDK
-可用 SDK:
-
-Py
-Python
-Java
-Java
-PHP
-PHP
-Go
-Go
-C#
-C#
-Node
-NodeJS
-JS
-Javascript
-部分 SDK 除了各接口的示例文档以外,还额外提供了调用 SDK 的示例应用程序。 示例应用程序提供了一个相对更加丰富的 SDK 使用示例,可以完整构建运行, 具体使用方式参考各 SDK 的示例程序说明
-
-Python(opens new window)
-Java(opens new window)
-C#(opens new window)
-Go(opens new window)
-#关于APIv4 Key升级
-2020 年 4 月
-
-APIv4 最开始合约的 Key 与现货的是分开管理的。不过从现在开始我们对 APIv4 的 Key 进行了升级改造。 用户现在可以创建多个 Key,而且可以为每个 Key 配置不同的操作权限。比如你可以创建一个 Key 同时拥有现货的读写和合约的读写权限,这样的话只需要一个 Key 就可以同时操作现货和合约交易。
-
-用户原有的 Key 会无缝迁移到新的管理方案,原先的 Key 在新的管理模式下,对应一个 Key 只配置了现货的权限,另一个 Key 只配置了合约的权限,用户可以使用新的管理模式对迁移后的 Key 重新配置权限。
-
-#与 APIv2 的区别
-APIv4 是一套全新的 HTTP REST API ,独立于 APIv2 。APIv4 提供了完整的交易功能,增强了 API 的认证鉴权。另外 APIv4 基于 OpenAPI 标准 (opens new window)书写,SDK 和文档通过同一套 API 标准生成,确保文档和程序的完整一致。
-
-APIv4 与 APIv2 在使用上有如下区别:
-
-两者的 API Key 是独立的。 APIv2 在个人账户的 APIKeys 入口申请。而 APIv4 在个人账户的 APIv4Keys 页面申请。
-APIv2 在交易操作上只支持现货交易,APIv4 支持现货、杠杆和合约的完整交易操作
-如何选择:
-
-如果需要杠杆或合约交易,选择 APIv4
-如果只需要现货交易或者钱包操作,则根据个人当前状况自行选择
-#市商申请
-为进一步提高平台盘口深度和交易流动性,我们将通过公开透明的方式招募机构做市商,根据为平台流动性做出的贡献情况,为专业机构做市商提供专业的做市商手续费率方案。
-
-提供 Gate UID
-提供他所交易量截图或VIP等级等
-简述做市方法及规模
-提供以上内容提交至 mm@gate.com ,我们将在3个工作日内受理。
-
-VIP11及以上需在个人中心开启GT抵扣,才可享有专业市商费率。
-
-#技术支持
-使用过程中如有问题或者建议,您可以选择以下任意方式联系我们:
-
-提交工单反馈
-在线工单反馈
-将您的联系方式与问题发送至 mm@gate.com ,我们将为您分配技术专员为您服务
-如您遇到API错误,建议您整理以下内容,方便我们为您快速分析问题:
-
-问题描述
-Gate UID
-请求的地址与参数
-错误代码
-返回结果
-即使是提交问题,也切勿将API key信息提交给客服及他人,否则会有严重的资产风险。如果已经不小心泄漏,请将已有API删除并重新生成。
-
-#Changelog
-v4.106.79
-
-2026-05-07
-
-补充统一账户快捷还款 definitions/unified/ 模型(QuickEstimatedRepayment、QuickRepaymentRequest、QuickRepaymentResponse、UnifiedQuickRepayDebtItem、UnifiedQuickRepayAvailableItem、UnifiedQuickRepayRepaidInfo、UnifiedQuickRepayUsedInfo)及 examples/unified/ 示例 JSON,与 unified-api.yaml 中 $ref 对齐,保证仓库内可解析及 collect/SDK/文档链路可用
-v4.106.78
-
-2026-05-04
-
-crossex-api.yaml:GET /crossex/coin_discount_rate(listCrossexCoinDiscountRate)的 summary 由「查询币种折扣率(分所模式下,保证金币种的折扣率)」精简为「查询币种折扣率」,去掉括号内的「分所模式/保证金币种」说明性补充
-v4.106.75
-
-2026-04-28
-
-p2p-merchant-api.yaml:示例与演示数据脱敏刷新(商家/对手方场景、含 SWIFT 等支付方式);示例字段命名与文档 schema 对齐(如 seller_realname、currency_type);精简冗长历史示例块
-quant-api.yaml:SpotGridStrategy.strategy_params_preview 的 additionalProperties 收紧为 type: string;SpotGridStrategyDetail 的 base_info、metrics、position 改为动态 additionalProperties 映射,不再 $ref 至 AIHubPortfolio*,并从本规格中移除独立的 AIHubPortfolioBaseInfo / AIHubPortfolioMetrics / AIHubPortfolioPosition 模型定义
-crossex-api.yaml:杠杆映射类响应的英文描述;账单流水分页接口移除查询参数 statement_type;列表项字段由 statement_type 更名为 type 并更新说明;精简 CrossexSymbol 等字段的中英描述措辞
-wallet-api.yaml:GET /wallet/withdraw_status 的 page 参数英文说明改为 “Page number”
-文档 i18n:抽取 P2P 商家接口新增文案并补齐英文 messages.po 译文
-v4.106.73
-
-2026-04-27
-
-Contract 模型(definitions/mercury/Contract.yaml):新增 enable_circuit_breaker,表示新上市合约是否启用标记价格熔断机制(平台若对某新开盘合约市场启用该机制以降低开盘后剧烈波动与爆仓风险,将提前公告)
-ContractStat 模型(definitions/mercury/ContractStat.yaml):新增 long_liq_usd_new、short_liq_usd_new(USDT 结算下按 long_liq_size / short_liq_size、multiplier 与 mark_price 计算的计价币种爆仓量);新增 top_long_size、top_short_size、long_taker_size、short_taker_size、top_long_account、top_short_account、long_users、short_users 等大户持仓、吃单量与用户数量类字段
-v4.106.72
-
-2026-04-27
-
-文档构建:新增 slate/gate/widdershins-split.yaml 与 slate/gate/zh_CN/widdershins-split.yaml,用于按 tag 拆分的 Widdershins 生成;移除 includedDocs,使每个 tag 子页仅包含该 tag 的路径与相关 schema(避免在每个 tag 页面重复注入 changelog/general/api/errors/authentication/faq 等通用章节);新增 tagGroups,为 TradFi tag 配置分组展示标题
-v4.106.71
-
-2026-04-27
-
-#统一账户 — 快捷还款(新增接口)
-新增 GET /unified/estimated_quick_repayment(getEstimatedQuickRepayment)— 返回预估快捷还款信息(按币种负债与可用于还款的币种及余额等)。
-新增 POST /unified/quick_repayment(createQuickRepayment)— 执行快捷还款;请求体为 debt_currencies、available_currencies 字符串数组。上述接口仅适用于统一账户 跨币种保证金模式 或 组合保证金模式。
-请求/响应拆至 definitions/unified/,title 与代码生成一致(QuickEstimatedRepayment、QuickRepaymentInfo、QuickRepaymentResp,数组元素类型 UnifiedDebtCurrencies、UnifiedAvailableCurrencies、RepaidInfo、UsedInfo;对应文件名 UnifiedQuickRepayDebtItem.yaml、UnifiedQuickRepayAvailableItem.yaml、UnifiedQuickRepayRepaidInfo.yaml、UnifiedQuickRepayUsedInfo.yaml),示例在 examples/unified/。
-两个接口均补充典型 400 / 401 / 403 响应,schema 使用 definitions/GateErrorResponse.yaml。
-文案修正:去掉重复「模式」,统一为「跨币种保证金模式与组合保证金模式」。
-#其他变更
-wallet-api.yaml:子账户余额列表接口查询参数 page 的英文说明更新
-futures-api.yaml:从 FuturesOrderAmendment 移除内部字段 contract,并精简改单请求示例
-crossex-api.yaml:摘要与示例更新,示例字段对齐(tif、fee_currency、avg_price 等);账户流水相关:去掉 statement_type 查询参数,响应字段更名为 type,及其他示例/文案调整
-quant-api.yaml:量化/网格策略相关 schema 与字段说明调整
-p2p-merchant-api.yaml:P2P 商家端接口路径与 schema 更新
-文档翻译:补全快捷还款 definitions 与 4xx 文案的英文词条,并同步修正快捷还款 scope 文案;另含量化接口「交易数量」多行说明等译文
-v4.106.70
-
-2026-04-21
-
-文档:BizType 参考表新增 5 个子账号内部资金划转 biz_id —— 150215、150216、150217、150218、150219(均归类为「子账号资金划转」)
-assetswap-api.yaml:新增响应包装 schema ConfigResp(GET /asset-swap/config 使用)和 OrderQueryV1Resp(GET /asset-swap/orders/v1/{id} 使用),对应响应中的 data $ref 切换到新 wrapper
-quant-api.yaml(SpotGridStrategy.strategy_params_preview、SpotGridStrategyDetail.base_info / metrics / position):将 additionalProperties 由强制 type: string 放宽为任意类型({});强类型 SDK 将由原本的 Map<String, String> 变为 Map<String, Object>
-v4.106.61
-
-2026-04-14
-
-SubAccountBalance 模型,新增 locking 字段(币种锁定金额)
-为 FuturesPriceTriggeredOrder、TriggerOrderResponse 补充 id_string 字段说明:与数值 id 表示同一自动订单,为 id 的十进制字符串,避免 JavaScript 等环境下 int64 精度问题;展示或需要字符串唯一标识时建议使用;与 futures.orders、futures.autoorders 等推送中同名字段含义一致。覆盖合约价格触发相关 REST:/futures/{settle}/price_orders(创建、列表、批量撤销、查询、撤销、修改)。
-PartnerCommissionHistory、AgencyCommissionHistory 中合伙人/代理商返佣列表项:将 commission_amount、commission_asset 字段说明由「交易金额」调整为「返佣金额」,与字段语义一致
-Contract 模型:补充 interest_rate 字段说明(字符串形式的小数比率),适用于 GET /futures/{settle}/contracts 与 GET /futures/{settle}/contracts/{contract} 返回
-开发者文档:将 Agent 相关文档品牌由 Gate for AI 更名为 Gate for AI Agent(页面标题、正文与侧栏文案);产品主页与帮助中心链接更新为 gate-for-ai-agent 路径
-v4.106.60
-
-2026-04-13
-
-文档翻译:补全双币理财相关接口与查询参数英文译文
-MCP 接口映射:新增 GET /earn/dual/project-recommend(getDualProjectRecommend)
-v4.106.59
-
-2026-04-10
-
-新增 GET /earn/dual/order-refund-preview(getDualOrderRefundPreview)— 双币投资提前赎回预览
-新增 POST /earn/dual/order-refund(placeDualOrderRefund)— 双币订单提前赎回
-新增 POST /earn/dual/modify-order-reinvest(modifyDualOrderReinvest)— 双币订单复投修改
-新增 GET /earn/dual/project-recommend(getDualProjectRecommend)— 双币推荐项目
-GET /earn/dual/investment_plan:新增可选查询参数 coin、type、quote_currency、sort、page、page_size
-GET /earn/dual/orders:新增可选查询参数 type、status、coin
-双币理财相关新增模型 DualOrderRefundPreview、DualOrderRefundParams、DualModifyOrderReinvestParams、DualProjectRecommend 及对应示例
-v4.106.58
-
-2026-04-03
-
-Contract 模型:新增 contract_type 字段 — 合约分类类型(如 stocks-股票、metals-金属、indices-指数、forex-外汇、commodities-大宗商品等)
-GET /wallet/sub_account_balances 接口:新增 page 和 limit 查询参数,支持分页
-v4.106.57
-
-2026-04-01
-
-WithdrawalRecord 模型:调整提现终态时间字段说明 — 当 status = DONE 时表示提现成功时间(不再与 block_number > 0 绑定)
-WithdrawalRecord、WithdrawalsDel 模型:精简 DONE 状态枚举说明(移除「block_number > 0 时表示已完成上链」的表述)
-GET /crossex/rule/risk_limits 返回:CrossexRiskLimitTier 新增必填字符串字段 quick_cal_amount(速算额)
-v4.106.56
-
-2026-03-31
-
-文档与翻译:修复英文 messages.po 重复条目与损坏的 msgid;对卡券中心两处超长 Markdown 说明清空不兼容的英文 msgstr(JSON 字面量中的 % 与 gettext 占位规则冲突,后续补全英文翻译)
-v4.106.55
-
-2026-03-30
-
-新增 GET /api/v4/rebate/partner/data/aggregated 接口(getPartnerAgentDataAggregated)— 合伙人代理数据聚合统计(返佣金额、交易量、净手续费、客户数;按业务类型可选返回交易人数)
-新增聚合返佣接口对应的 PartnerDataAggregated、PartnerDataAggregatedResponse 模型定义
-v4.106.54
-
-2026-03-20
-
-新增 POST /api/v4/earn/autoinvest/plans/create 接口 - 创建定投计划
-新增 POST /api/v4/earn/autoinvest/plans/update 接口 - 更新定投计划
-新增 POST /api/v4/earn/autoinvest/plans/stop 接口 - 停止定投计划
-新增 POST /api/v4/earn/autoinvest/plans/add_position 接口 - 立即加仓
-新增 GET /api/v4/earn/autoinvest/coins 接口 - 查询支持定投的币种
-新增 POST /api/v4/earn/autoinvest/min_invest_amount 接口 - 查询可投资的最小金额
-新增 GET /api/v4/earn/autoinvest/plans/records 接口 - 查询计划执行记录
-新增 GET /api/v4/earn/autoinvest/orders 接口 - 查询计划执行记录详情(订单明细)
-新增 GET /api/v4/earn/autoinvest/config 接口 - 查询投资币种配置
-新增 GET /api/v4/earn/autoinvest/plans/detail 接口 - 查询定投计划详情
-新增 GET /api/v4/earn/autoinvest/plans/list_info 接口 - 查询定投计划列表
-v4.106.52
-
-2026-03-29
-
-FuturesInitialOrder 模型:新增可选 amount 字段(字符串),用于小数合约张数;与 size 同时存在时以 amount 为准
-FuturesUpdatePriceTriggeredOrder 模型:新增可选 amount 字段(字符串),语义与 size 相同
-SpotPricePutOrder 模型:将 time_in_force 列入必填字段
-v4.106.51
-
-2026-03-27
-
-文档站点新增 Gate for AI 开发者指南菜单:全面指导 AI Agent 通过 MCP(Model Context Protocol)协议与 CLI 工具接入 Gate.io API
-文档包含:MCP 服务端点、AI Skills(40+ 预置工作流)、接入方式(Cursor、Claude、CLI)、鉴权方式、代码示例等
-v4.106.50
-
-2026-03-26
-
-下线理财 ETH2 质押相关接口:POST /earn/staking/eth2/swap(swapETH2)、GET /earn/staking/eth2/rate_records(rateListETH2)
-下线理财结构性产品相关接口:GET /earn/structured/products(listStructuredProducts)、GET /earn/structured/orders(listStructuredOrders)、POST /earn/structured/orders(placeStructuredOrder)
-移除上述功能在 definitions/earn/、examples/earn/ 下的相关模型定义与示例
-v4.106.49
-
-2026-03-25
-
-新增 FuturesOrderTimerange 模型;GET /futures/{settle}/orders_timerange 返回列表项 schema 由 FuturesOrder 调整为 FuturesOrderTimerange
-FuturesOrder 模型:order_value、trade_value 设为只读并标记 x-external: false(公开 SDK 不包含)
-GET /futures/{settle}/orders/{order_id}:优化路径参数说明(按订单 ID / 自定义 text 查询的规则)
-v4.106.48
-
-2026-03-25
-
-Currency 模型:新增 category 字段(字符串数组,币种分类,取值示例见字段说明:stocks/metals/indices/forex/commodities 等)
-v4.106.45
-
-2026-03-20
-
-BatchOrder 模型:完善 finish_as 字段 ioc 和 poc 枚举值描述,准确反映基于 time_in_force 设置的订单撤销原因
-Order 模型:完善 finish_as 字段 ioc 和 poc 枚举值描述,准确反映基于 time_in_force 设置的订单撤销原因
-UnifiedAccount 模型:新增 mode 字段(统一账户模式:经典账户/跨币种保证金/组合保证金/单币种保证金)
-UnifiedAccount 模型:新增 balance_version 字段(余额版本号)
-UnifiedAccount 模型:优化 available、freeze、equity、iso_balance 等多个保证金相关字段的描述
-更新 UidPushWithdrawalResp 模型:id 字段类型从 integer (int64) 变更为 string
-CrossEx API GET /crossex/fee 费率接口:响应结构调整为数组形式,支持返回多个交易所(BINANCE、OKX、GATE、BYBIT)的费率信息,新增 exchange_type 字段标识交易所类型
-CrossEx API POST /crossex/convert 闪兑接口:响应新增 order_id(订单号)和 text(订单号文本)字段
-CrossEx API 利率扣息类型说明优化:interest_type 字段新增 PERIODIC_ISOLATED 枚举值(整点负债收息)
-v4.106.44
-
-2026-03-20
-
-更新 TradFi API:GET /tradfi/symbols/detail(querySymbolDetail)查询交易对详情接口改为需认证(移除 security: [])
-v4.106.43
-
-2026-03-19
-
-新增理财定期 API:GET /earn/fixed-term/product(listEarnFixedTermProducts)、GET /earn/fixed-term/product/{asset}/list(listEarnFixedTermProductsByAsset)、POST /earn/fixed-term/user/lend(createEarnFixedTermLend)、GET /earn/fixed-term/user/lend(listEarnFixedTermLends)、POST /earn/fixed-term/user/pre-redeem(createEarnFixedTermPreRedeem)、GET /earn/fixed-term/user/history(listEarnFixedTermHistory)
-FuturesUpdatePriceTriggeredOrder 模型:order_id 字段新增 format: int64
-futures-auto-order-api.yaml:价格触发订单响应 ID schema 新增 format: int64
-parameters.yaml:pos_margin_mode 和 dual_side 参数从选填改为必填
-v4.106.42
-
-2026-03-19
-
-UnifiedAccount 模型:新增 mode 字段(统一账户模式:经典账户/跨币种保证金/组合保证金/单币种保证金)
-UnifiedAccount 模型:新增 balance_version 字段(余额版本号)
-UnifiedAccount 模型:优化 available、freeze、equity、iso_balance 等多个保证金相关字段的描述
-v4.106.38
-
-2026-03-14
-
-更新 amendOptionsOrder 请求体:新增必填字段 contract(期权合约名称)
-v4.106.36
-
-2026-03-13
-
-新增 PUT /options/orders/{order_id} 期权改单接口(amendOptionsOrder)
-更新 TradFi API:GET /tradfi/users/mt5-account 查询 mt5 账号信息接口改为需认证(移除 security: [])
-v4.106.34
-
-2026-03-12
-
-更新 Alpha API /alpha/orders 查询订单接口:currency、side、status 参数从必填改为选填
-CrossEx API 新增支持 BYBIT 交易所
-v4.106.33
-
-2026-03-10
-
-BrokerCommission、BrokerTransaction 模型:source 字段新增 TradFi 类型(返佣交易类型:Spot、Futures、Options、Alpha、TradFi)
-v4.106.32
-
-2026-03-05
-
-更新 P2P Merchant API:请求内容类型从 multipart/form-data 改为 application/json,请求体 schema 提取到独立定义文件
-更新 P2P Merchant API:移除各接口独立的 security: [],改为继承全局 apiv4 认证
-更新 P2P Merchant API:complete_rate_month、orders_buy_rate_month、transactions_month、transactions_all 字段类型从 integer 改为 number
-v4.106.31
-
-2026-03-03
-
-PUT /futures/{settle}/price_orders/{order_id} 接口路径变更为 PUT /futures/{settle}/price_orders/amend/{order_id}
-FuturesUpdatePriceTriggeredOrder 模型:order_id 字段类型从 string 变更为 integer
-BatchOrder 模型:finish_as 字段新增枚举值:liquidate_cancelled(爆仓撤销)、small(数量太小)、depth_not_enough(深度不足)、trader_not_enough(对手方不足)、poc(未满足挂单策略)、fok(未完全成交)、price_protect_cancelled(价格保护撤单)、unknown(未知)
-Order 模型:更新 cancelled_reason 字段中 ioc 枚举值的描述,明确该状态也适用于 poc/rvt/rat/rpi 类型订单被判定为 taker 而拒绝的场景
-v4.106.30
-
-2026-03-03
-
-PUT /futures/{settle}/price_orders/{order_id} 接口路径变更为 PUT /futures/{settle}/price_orders/amend/{order_id}
-FuturesUpdatePriceTriggeredOrder 模型:order_id 字段类型从 string 变更为 integer
-v4.106.29
-
-2026-03-02
-
-CrossEx API 所有接口路径新增 /crossex 前缀
-POST /crossex/orders 接口:限频描述新增最大挂单数限制(1,000 个)
-GET /crossex/positions/leverage 接口:响应结构从数组改为 Map
-GET /crossex/margin_positions/leverage 接口:响应结构从数组改为 Map
-平仓接口从 DELETE /position 变更为 POST /crossex/position
-POST /unified/portfolio_calculator 接口:更新描述,支持所有已开放期权交易的标的物币种
-MockSpotBalance 模型:equity 字段描述移除币种限制
-MockSpotOrder 模型:count 字段描述移除币种限制
-MockFuturesPosition、MockFuturesOrder 模型:contract 字段描述更新为支持所有已开放期权交易的标的物的USDT永续合约
-MockOptionsPosition、MockOptionsOrder 模型:options_name 字段描述更新为支持所有期权合约市场
-v4.106.28
-
-2026-02-28
-
-更新翻译内容,优化TradFi文档描述
-v4.106.27
-
-2026-02-26
-
-新增闪兑相关错误码文档
-新增币种 total_supply(总供应量)和 market_cap(市值)字段描述
-Contract 模型:新增 funding_impact_value 字段(资金费用深度影响额)
-FuturesBBOOrder 模型:删除 limit_vip 字段
-v4.106.26
-
-2026-02-12
-
-新增 P2P Merchant API 接口:POST /p2p/merchant/books/ads_list(获取广告列表)
-v4.106.25
-
-2026-02-11
-
-POST /earn/dual/orders 接口:分离请求和响应模型
-新增 PlaceDualInvestmentOrderParams 模型(双币理财下单请求参数)
-PlaceDualInvestmentOrder 模型:新增响应字段(id、copies、invest_amount、settlement_amount、create_time、complete_time、status、invest_currency、exercise_currency、exercise_price、settlement_price、settlement_currency、apy_display、apy_settlement、delivery_time)
-DualGetPlans 模型:标记 per_value 字段为已废弃
-v4.106.24
-
-2026-02-09
-
-新增 OTC API 接口:POST /otc/quote(法币和稳定币询价)、POST /otc/order/create(法币下单)、POST /otc/stable_coin/order/create(稳定币下单)、GET /otc/get_user_def_bank(获取用户默认银行卡信息)、GET /otc/bank_list(获取用户银行卡列表)、POST /otc/order/paid(法币订单设置已付款)、POST /otc/order/cancel(法币订单取消)、GET /otc/order/list(法币订单列表)、GET /otc/stable_coin/order/list(稳定币订单列表)、GET /otc/order/detail(法币订单详情)
-v4.106.23
-
-2026-02-06
-
-OptionsOrder 模型:为 id 字段添加 x-is-bigint: true 标记,确保 JavaScript SDK 正确处理大数类型
-v4.106.22
-
-2026-02-03
-
-Order 模型:新增 price_protect_cancelled 状态,表示因价格保护导致撤单的订单
-v4.106.21
-
-2026-02-03
-
-更新子账户划转及划转记录相关 amount 字段描述
-v4.106.20
-
-2026-02-02
-
-新增合约追踪委托接口:POST /futures/{settle}/autoorder/v1/trail/create、POST /futures/{settle}/autoorder/v1/trail/stop、POST /futures/{settle}/autoorder/v1/trail/stop_all、GET /futures/{settle}/autoorder/v1/trail/list、GET /futures/{settle}/autoorder/v1/trail/detail、POST /futures/{settle}/autoorder/v1/trail/update、GET /futures/{settle}/autoorder/v1/trail/change_log
-新增 TrailOrder、TrailChangeLog 模型(追踪委托及改单记录)
-SwapCoin 模型:side 字段类型改为 integer(0-质押、1-赎回),移除 pid 的 int32 格式限制
-新增 BatchFundingRatesRequest、BatchFundingRatesResponse 模型(批量查询资金费率的请求/响应结构)
-FuturesAccount 模型:删除 cross_settle 字段
-TotalBalance 模型:新增账户类型(meme_box、options、payment)
-UnifiedMarginTiers 模型:修复描述格式
-GET /futures/{settle}/funding_rate 接口:时间间隔枚举新增 10s 选项
-v4.106.19
-
-2026-01-27
-
-Contract 模型,新增 enable_decimal 字段,用于标识是否支持小数字符串类型合约张数。当该字段为 true 时,表示该合约支持小数张数(即 size 字段可以使用小数字符串类型);当为 false 时,表示该合约不支持小数张数(即 size 字段只能使用整数类型)
-v4.106.18
-
-2026-01-26
-
-更新 API 文档:添加现货限频规则说明章节,包括现有限频规则、新增限频规则和成交率计算公式
-新增 P2P Merchant API 接口:POST /p2p/merchant/account/get_user_info(获取账户信息)、POST /p2p/merchant/account/get_counterparty_user_info(获取对手方信息)、POST /p2p/merchant/account/get_myself_payment(获取支付方式列表)、POST /p2p/merchant/transaction/get_pending_transaction_list(获取进行中订单)、POST /p2p/merchant/transaction/get_completed_transaction_list(获取所有/历史订单)、POST /p2p/merchant/transaction/get_transaction_details(查询订单详情)、POST /p2p/merchant/transaction/confirm-payment(确认付款)、POST /p2p/merchant/transaction/confirm-receipt(确认收款)、POST /p2p/merchant/transaction/cancel(取消订单)、POST /p2p/merchant/books/place_biz_push_order(发布广告挂单)、POST /p2p/merchant/books/ads_update_status(广告单状态更新)、POST /p2p/merchant/books/ads_detail(查询广告详情)、POST /p2p/merchant/books/my_ads_list(获取我的广告列表)、POST /p2p/merchant/chat/get_chats_list(获取聊天记录)、POST /p2p/merchant/chat/send_chat_message(发送文本消息)、POST /p2p/merchant/chat/upload_chat_file(上传聊天文件)
-v4.106.17
-
-2026-01-22
-
-GET /loan/multi_collateral/currency_quota 接口,CurrencyQuota 模型新增两个返回字段:left_quota_fixed(定期币种剩余可借/质押限额)和 left_quote_usdt_fixed(定期币种换算成USDT的剩余币种限额)
-下线:移除单币抵押借币 API 接口(/loan/collateral/**)。这些接口已不再可用。
-FuturesUpdatePriceTriggeredOrder 模型:order_id 字段类型修改为字符串,新增 close 字段
-SpotPriceTrigger 模型:expiration 字段从必填项中移除
-v4.106.16
-
-2026-01-20
-
-更新订单状态描述:将订单模型(mercury 和 pilot 模块中的 BatchOrder、InternalOrder、Order、OrderCancel,以及 portfolio 模块中的 PortfolioSpotOrders)中 "closed" 状态的描述从 "全部成交" 改为 "已结束的订单",使描述更加清晰准确
-v4.106.15
-
-添加crossex菜单、其子菜单websocket和rest页
-新增完整的crossex API端点,支持跨交易所交易,包括订单管理、仓位管理、账户管理和历史数据查询
-实现crossex WebSocket支持,提供实时市场数据和订单更新
-v4.106.14
-
-Order 模型,text 字段描述更新,补充强平订单场景说明(pm_liquidate、comb_margin_liquidate、scm_liquidate 这三种场景代表全仓强平订单,liquidate 代表逐仓强平订单)
-Trade 模型,text 字段描述更新,补充强平订单场景说明(pm_liquidate、comb_margin_liquidate、scm_liquidate 这三种场景代表全仓强平订单,liquidate 代表逐仓强平订单)
-v4.106.13
-
-新增 OTC API 接口:POST /otc/quote(法币和稳定币询价)、POST /otc/order/create(法币下单)、POST /otc/stable_coin/order/create(稳定币下单)、GET /otc/get_user_def_bank(获取用户默认银行卡信息)、POST /otc/order/paid(法币订单设置已付款)、POST /otc/order/cancel(法币订单取消)、GET /otc/order/list(法币订单列表)、GET /otc/stable_coin/order/list(稳定币订单列表)、GET /otc/order/detail(法币订单详情)、GET /otc/stable_coin/order/detail(稳定币订单详情)、GET /otc/get_api_order_uid(获取通过api/v4接口下单的用户)
-修复 OTC API 规范:为所有接口添加 operationId,将 requestBody 内容类型从 multipart/form-data 更新为 application/json,为所有 tags 和 responses 添加描述,配置 servers 和 security 方案
-v4.106.12
-
-新增 GET /earn/dual/balance 接口,查询双币理财资产
-新增 GET /futures/{settle}/get_leverage/{contract} 接口,获取指定模式的杠杆信息
-新增 POST /futures/{settle}/positions/{contract}/set_leverage 接口,更新指定模式的杠杆,简化leverage接口复杂逻辑
-新增 POST /futures/{settle}/set_position_mode 接口,设置持仓模式,替换dual_mode接口
-POST /futures/{settle}/positions/{contract}/reverse 接口,新增 pos_margin_mode 参数(仓位保证金模式,分仓模式必传,取值isolated/cross)
-FuturesAccount 模型,新增 enable_dual_plus 字段,表示是否支持分仓模式
-FuturesAccount 模型,position_mode 字段描述更新,明确持仓模式:single-单向持仓,dual-双向持仓,dual_plus-分仓
-FuturesOrder 模型,新增 pos_margin_mode 字段,表示仓位保证金模式(isolated - 逐仓, cross - 全仓,只在简易分仓模式下传递)
-Position 模型,新增 pos_margin_mode 字段,表示仓位保证金模式(isolated - 逐仓, cross - 全仓)
-Position 模型,新增 lever 字段,表示仓位当前杠杆,逐仓和全仓都可以该字段表示,逐步替换当前的leverage和cross_leverage_limit
-新增 FuturesLeverage 模型定义,用于杠杆查询响应
-v4.106.11
-
-BatchOrder、CurrencyPair、Order 模型中 slippage 字段描述更新,明确为现货市价下单支持的最大滑点比率,以下单时的市场最新价格为基准计算(示例:0.03即3%)
-POST /spot/batch_orders 接口,响应描述更新,说明响应包含多个订单对象,订单对象具体结构参考 /spot/orders 下单接口的结构
-v4.106.10
-
-GET /account/rate_limit 接口,新增描述说明该接口暂未开放使用
-GET /wallet/order_status 接口,更新接口说明和描述,明确为查询主子账户划转状态
-v4.106.9
-
-PUT /futures/{settle}/price_orders/{order_id} 接口,修复请求体模型 FuturesUpdatePriceTriggeredOrder 字段名错误:contact 字段改为 order_id,并将 order_id 字段标记为必填
-POST /loan/collateral/orders 接口标记为已废弃/下线
-v4.106.8
-
-Contract 模型,新增 market_order_slip_ratio 字段,表示合约市价下单支持的最大滑点比率,比率计算以市场最新价格为基准
-Contract 模型,新增 market_order_size_max 字段,表示合约市价下单支持的最大张数,默认值为0,为默认值时取order_size_max字段作为最大张数限制
-FuturesOrder 模型,新增 market_order_slip_ratio 字段,表示市价下单自定义最大滑点比率,不传和未返回表示使用合约默认配置
-BatchFuturesOrder 模型,新增 market_order_slip_ratio 字段,表示订单响应中返回的最大滑点比率
-v4.106.7
-
-Contract 模型,新增 market_order_slip_ratio 字段,表示合约市价下单支持的最大滑点比率,比率计算以市场最新价格为基准
-Contract 模型,新增 market_order_size_max 字段,表示合约市价下单支持的最大张数,默认值为0,为默认值时取order_size_max字段作为最大张数限制
-FuturesOrder 模型,新增 market_order_slip_ratio 字段,表示市价下单自定义最大滑点比率,不传和未返回表示使用合约默认配置
-BatchFuturesOrder 模型,新增 market_order_slip_ratio 字段,表示订单响应中返回的最大滑点比率
-GET /unified/batch_borrowable 接口,currencies 参数添加 style: form 和 explode: false,优化数组参数格式
-GET /unified/estimate_rate 接口,currencies 参数添加 style: form 和 explode: false,优化数组参数格式
-GET /loan/multi_collateral/current_rate 接口,currencies 参数添加 style: form 和 explode: false,优化数组参数格式
-更新限频规则文档:在钱包私有接口限频规则中新增 POST /withdrawals/push 接口限频说明(1r/10s)
-v4.106.6
-
-GET /options/order_book 接口响应模型从 FuturesOrderBook 更新为 OptionsOrderBook,实现期权与合约 API 的更好分离
-GET /options/trades 接口响应模型从 FuturesTrade 更新为 OptionsTrade,实现期权与合约 API 的更好分离
-GET /options/candlesticks 接口响应模型从 FuturesCandlestick 更新为 OptionsCandlestick,实现期权与合约 API 的更好分离
-新增 OptionsOrderBook 和 OptionsTrade 模型定义,为期权 API 响应提供专门的模型
-v4.106.5
-
-新增资产流水编码:150102(币种回购-扣款)、150101(币种回购-加款)、143(币种更名扣款)、144(币种更名加款)、707(现货同币种结算-转出)、708(现货同币种结算-转入)
-v4.106.4
-
-CurrencyPair 模型,新增 up_rate 和 down_rate 字段,展示报价最大涨跌幅百分比
-Contract 模型,新增 funding_rate_limit 字段,表示资金费率上限值
-v4.106.3
-
-GET /futures/{settle}/accounts 接口说明更新,支持查询经典合约账户和统一账户
-PUT /futures/{settle}/accounts 接口,enable_evolved_classic 字段标记为已废弃
-GET /futures/{settle}/positions/{contract} 接口说明更新,明确在同一合约市场下持有双向仓位时的查询方式
-POST /futures/{settle}/positions/{contract}/margin 接口说明更新,附加新风险限额规则链接,说明应使用杠杆调整接口而非直接修改保证金
-POST /futures/{settle}/positions/{contract}/leverage 接口参数说明更新,明确 leverage 参数(用于逐仓,需要 cross_leverage_limit 为空)和 cross_leverage_limit 参数(用于全仓,需要 leverage 设为 0)
-POST /futures/{settle}/dual_comp/positions/{contract}/risk_limit 接口说明更新,附加风险限额规则链接
-GET /options/accounts 接口说明更新,支持查询经典期权账户和统一账户
-Position 模型字段描述更新,优化杠杆和风险管理相关说明:leverage(逐仓杠杆倍数,0 表示全仓模式)、leverage_max(基于当前仓位规模的最大杠杆)、maintenance_rate(梯度式维持保证金率计算)、liq_price(预估强平价,仅供参考)、initial_margin 和 maintenance_margin(扩大适用范围说明)、realised_pnl(详细说明包含平仓结算、资金费和手续费)、pnl_pnl(平仓结算盈亏)、pnl_fund(资金费盈亏)、pnl_fee(总手续费)、history_pnl(所有历史平仓结算盈亏)、cross_leverage_limit(简化说明)
-FuturesAccount 和 DeliveryAccount 模型更新:total 字段更新说明"仅适用于经典合约账户",position_margin 标记为已废弃,order_margin 更新为"所有未完成订单的起始保证金",enable_evolved_classic 和 enable_new_dual_mode 标记为已废弃,margin_mode 枚举值扩展新增值 3(单币种保证金模式)
-OptionsAccount 模型更新:total 和 equity 字段添加统一账户限制说明,liq_triggered 描述更新为"账户是否处于强平状态",margin_mode 枚举值扩展新增值 3,unrealised_pnl 描述增强附带计算公式
-MarginAccount 模型更新:account_type 描述更新删除"risk"选项,risk 字段标记为已废弃,mmr 描述优化
-Contract 和 DeliveryContract 模型更新:quanto_multiplier 概念更新为"合约乘数",maintenance_rate 明确为"第一档维持保证金率要求",mark_type 和 funding_cap_ratio 标记为已废弃,mark_price_round 简化为"标记价格的最小单位"
-OptionsContract 模型更新:tag 更新为"到期周期,有 day、week、month",multiplier 更新为"期权合约乘数",underlying_price 更新为"对应交割日期的远期期货价格",mark_price_round 简化说明,order_price_deviate 和 trade_id 标记为已废弃,orders_limit 优化为"每个用户在该盘口最多可挂的订单数量"
-FuturesTicker 和 DeliveryTicker 模型更新:quanto_base_rate 字段标记为已废弃
-OptionsTicker 模型更新:leverage 计算公式更新并添加参考说明
-FuturesTrade 和 DeliveryTrade 模型更新:is_internal 字段标记为已废弃
-OptionsMyTrade 和 OptionsPosition 模型更新:underlying_price 字段更新为"对应交割日期的远期期货价格"
-PositionTimerange 模型更新:leverage_max 和 maintenance_rate 描述优化
-FuturesAutoDeleverage 模型更新:leverage 和 cross_leverage_limit 描述明确,更好理解保证金模式
-风险限额梯度模型更新(FuturesRiskLimitTier、FuturesLimitRiskTiers、DeliveryLimitRiskTiers):统一 maintenance_rate 描述为"第一档维持保证金率要求"
-MarginLeverageTier 模型更新:优化 upper_limit(基于杠杆的最大借币限额)、mmr(梯度保证金要求下的综合维持保证金率)和 leverage(基于当前负债规模的最大杠杆倍数)描述
-CreateUniLoan 和 UniLoanInterestRecord 模型更新:type 字段描述更新为"借贷类型,margin 表示为杠杆借币"
-v4.106.2
-
-新增 GET /wallet/getLowCapExchangeList 接口,获取低价值币种列表
-v4.106.1
-
-Position 和 FuturesAutoDeleverage 模型中 leverage 和 cross_leverage_limit 字段描述更新,明确全仓/逐仓模式下的使用说明
-POST /futures/{settle}/positions/{contract}/leverage 接口中 leverage 和 cross_leverage_limit 参数描述更新,明确使用要求
-PUT /sub_accounts/{user_id}/keys/{key} 接口说明更新,提示此接口无法修改 mode 账户类型属性
-v4.106.0
-
-为解决支持小数下单问题,将所有 Futures 相关接口中的 size、数量相关字段从 integer 类型统一改为 string 类型。受影响的模型包括:FuturesOrder(size、iceberg、left)、BatchFuturesOrder(size、iceberg、left)、Position(size、trade_long_size、trade_short_size)、PositionTimerange(size)、MyFuturesTrade(size、close_size)、MyFuturesTradeTimeRange(size、close_size)、FuturesTrade(size)、FuturesOrderBook(asks 和 bids 中的 size)、FuturesCandlestick(v)、FuturesLiquidate(size、order_size)、FuturesLiqOrder(position_size、size、order_size)、FuturesAutoDeleverage(size、entry_size)、FuturesCollusionOrder(size、left)、FuturesBatchAmendOrderRequest(size)、Contract(order_size_min、order_size_max、trade_size、position_size)、ContractStat(long_liq_size、short_liq_size、open_interest)
-Position 模型中新增 pid 字段,用于分仓仓位 ID
-所有语言 SDK(Go、C#、Java、Python、PHP、TypeScript)统一添加 X-Gate-Size-Decimal: 1 默认请求头,确保服务端正确处理 size 字段
-新建 12 个独立的 Delivery Schema 文件,用于分离 Delivery 和 Futures 对象:DeliveryAccount、DeliveryAccountBook、DeliveryOrder、DeliveryOrderBook、DeliveryPosition、DeliveryPositionClose、DeliveryTrade、DeliveryMyTrade、DeliveryLiquidate、DeliveryInsuranceRecord、DeliveryLimitRiskTiers、DeliveryCloseAllPositionsResponse
-v4.105.32
-
-POST /futures/{settle}/positions/{contract}/leverage 接口描述更新,新增仓位模式切换规则详解、使用示例和风险警告,提升接口使用的安全性和清晰度
-v4.105.31
-
-TradeFee 模型中 taker_fee 和 maker_fee 字段描述更新,明确为现货交易费率
-v4.105.29
-
-GET /spot/my_trades 接口响应中新增 deal 字段,显示本次成交总额
-GET /unified/accounts 接口响应中新增 options_order_loss 字段,显示期权挂单损失(单位USDT),在组合保证金模式下有效,接口响应中 spot_order_loss 字段描述更新,明确表示现货挂单损失,在跨币种模式和组合保证金模式下有效, cross_balance 和 iso_balance 字段描述更新,现在在单币种保证金模式、跨币种保证金模式下均有效
-v4.105.28
-
-DELETE /withdrawals/{withdrawal_id} 接口响应中新增 block_number 字段,显示区块编号
-GET /unified/accounts 接口响应中 cross_balance 和 iso_balance 字段描述更新,现在在单币种保证金模式、跨币种保证金模式下均有效
-v4.105.27
-
-更新 DepositRecord、WithdrawalRecord 和 WithdrawalsDel 模型中 status 字段的描述,使其更加清晰
-充值状态枚举中移除 FINAL 状态,优化 DONE 状态描述
-v4.105.24
-
-GET /wallet/currency_chains 接口描述更新,流通性或者价值极低的币种不支持api操作,请通过Web或App页面进行查询以及处理
-GET /wallet/withdraw_status 接口描述更新,流通性或者价值极低的币种不支持api操作,请通过Web或App页面进行查询以及处理
-v4.105.20
-
-DELETE /withdrawals/{withdrawal_id} 接口响应模型更新为使用 WithdrawalsDel 结构
-GET /wallet/deposits 接口响应中新增 BLOCKED、DEP_CREDITED、FINAL 状态值
-GET /wallet/currency_chains 接口响应中新增 is_deposit_disabled 字段
-v4.105.19
-
-GET /spot/currency_pairs 和 GET /spot/currency_pairs/{currency_pair} 接口,fee 字段标记为已废弃
-POST /earn/staking/eth2/swap 接口描述从"ETH2兑换"更新为"ETH兑换",ETH2更名为GTETH
-GET /earn/staking/eth2/rate_records 接口描述更新为查询GTETH历史收益率
-v4.105.18
-
-新增 PUT /futures/{settle}/price_orders 接口,用于修改单个价格触发订单
-修改价格触发订单请求中新增 settle、order_id、size、price、trigger_price、price_type 和 auto_size 参数
-v4.105.11
-
-新增 GET /account/main_keys 接口,查询主账户所有API Key信息
-GET /spot/currency_pairs 和 GET /spot/currency_pairs/{currency_pair} 接口,fee 字段标记为已废弃
-v4.105.10
-
-新增 POST /futures/{settle}/bbo_orders 接口,档位BBO合约下单功能
-POST /futures/{settle}/price_orders 接口,合约价格触发单中的 price 和 rule 字段更新为必填
-v4.105.9
-
-GET /futures/{settle}/positions 接口,返回值增加 settlement_currency 字段,支持多结算币种
-POST /earn/uni/lends 接口,请求参数新增 auto_renew 字段,支持自动续借功能
-GET /spot/trades 接口,查询参数新增 trade_type 字段,支持按交易类型过滤
-v4.105.8
-
-GET /unified/accounts 接口,返回值增加 margin_mode 字段,标识账户保证金模式
-GET /spot/my_trades 接口,返回值增加 fee_currency 字段,显示手续费币种
-v4.105.7
-
-GET /futures/{settle}/positions 接口,返回值增加 liquidation_price 字段,用于风险管理
-POST /spot/orders 接口,请求参数新增 stop_loss 和 take_profit 字段,支持高级订单类型
-GET /unified/accounts 接口,返回值增加 total_balance 字段,显示总余额
-v4.105.6
-
-新增 GET /wallet/saved_address 接口,查询已保存的提现地址
-GET /wallet/withdrawals 接口,返回值增加 network_fee 字段,显示网络手续费
-GET /spot/currency_pairs 接口,返回值增加 min_amount 和 max_amount 字段,显示交易限额
-v4.105.5
-
-GET /futures/{settle}/orders 接口,返回值增加 order_type 字段,区分订单类型
-GET /spot/candlesticks 接口,interval 参数新增支持 30s 时间间隔
-GET /margin/accounts 接口,返回值增加 available_balance 字段,显示可用余额
-v4.105.4
-
-GET /futures/{settle}/tickers 接口,返回值增加 funding_rate_next 字段,显示下期资金费率
-GET /unified/accounts 接口,返回值增加 cross_leverage 字段,显示全仓杠杆倍数
-v4.105.3
-
-GET /futures/{settle}/positions 接口,查询参数新增 position_side 字段,支持对冲模式
-GET /earn/dual/orders 接口,查询参数新增 investment_type 字段,按投资类型过滤
-GET /futures/{settle}/accounts 接口,返回值增加 unrealized_pnl 字段,显示未实现盈亏
-v4.105.2
-
-GET /spot/fee 接口,返回值增加 maker_fee_rate 和 taker_fee_rate 字段,显示手续费率
-GET /futures/{settle}/contracts 接口,返回值增加 settle_currency 字段,显示结算币种
-v4.105.1
-
-POST /futures/{settle}/orders 接口,请求参数新增 time_in_force 字段,设置订单有效期类型
-GET /wallet/deposits 接口,查询参数新增 network 字段,按网络过滤充值记录
-v4.105.0
-
-GET /unified/accounts 接口,返回值增加 portfolio_margin 字段,显示组合保证金信息
-POST /futures/{settle}/positions/mode 接口,请求参数新增 position_mode 字段,设置持仓模式
-v4.104.9
-
-POST /futures/{settle}/orders 接口,请求参数新增 reduce_only 字段,支持只减仓订单
-GET /spot/orders 接口,查询参数新增 account_type 字段,按账户类型过滤
-GET /futures/{settle}/accounts 接口,返回值增加 funding_balance 字段,显示资金余额
-v4.104.8
-
-GET /earn/uni/currencies 接口,返回值增加 apr 字段,显示年化收益率
-GET /earn/dual/investment_plan 接口,返回值增加 lock_period 字段,显示锁定期
-v4.104.7
-
-GET /spot/order_book 接口,返回值增加 order_book_id 字段,用于订单簿版本控制
-POST /wallet/transfers 接口,请求参数新增 client_order_id 字段,支持客户端订单ID
-GET /spot/accounts 接口,返回值增加 trading_fee_rate 字段,显示交易手续费率
-v4.104.6
-
-GET /futures/{settle}/tickers 接口,返回值增加 mark_price 字段,显示标记价格
-新增 GET /futures/{settle}/insurance 接口,查询保险基金信息
-GET /futures/{settle}/positions 接口,返回值增加 isolated_margin 字段,显示逐仓保证金
-v4.104.5
-
-GET /spot/my_trades 接口,返回值增加 order_id 字段,用于交易与订单关联
-GET /unified/loans 接口,查询参数新增 currency 字段,按币种过滤借贷记录
-GET /unified/accounts 接口,返回值增加 borrow_amount 字段,显示借贷金额
-v4.104.4
-
-GET /spot/price_orders 接口,返回值增加 trigger_price 字段,显示触发价格
-GET /futures/{settle}/contracts 接口,返回值增加 maintenance_rate 字段,显示维持保证金率
-v4.104.3
-
-GET /futures/{settle}/positions 接口,查询参数新增 hedge_mode 字段,支持对冲模式查询
-GET /earn/dual/orders 接口,查询参数新增 status 字段,按状态过滤订单
-GET /unified/accounts 接口,返回值增加 cross_margin_leverage 字段,显示全仓杠杆倍数
-v4.104.2
-
-GET /futures/{settle}/my_trades 接口,返回值增加 settlement_size 字段,显示结算数量
-新增 GET /wallet/total_balance 接口,查询账户总余额
-GET /margin/accounts 接口,返回值增加 available_margin 字段,显示可用保证金
-v4.104.1
-
-POST /spot/orders 接口,请求参数新增 post_only 字段,支持只做maker订单
-GET /futures/{settle}/orders 接口,查询参数新增 contract 字段,按合约过滤订单
-GET /futures/{settle}/funding_rate 接口,返回值增加 funding_time 字段,显示资金费率时间
-v4.104.0
-
-新增 GET /unified/risk_units 接口,统一账户风险单位计算
-GET /unified/accounts 接口,返回值增加 risk_level 字段,显示风险等级
-POST /unified/orders 接口,请求参数新增 auto_borrow 字段,支持自动借贷
-v4.103.0
-
-GET /spot/account_book 接口新增 code 查询参数和响应字段,支持按特定编码过滤账户流水记录
-closeAllPositions 操作新增 text 参数,支持在一键平仓时添加订单备注
-新增资产流水编码详细文档,包含超过300个交易编码的详细说明
-v4.102.6
-
-优化赚币兑换响应结构 SwapCoinStruct,新增 pid、subtype、exchange_amount、updateStamp、protocol_type、client_order_id、source 字段
-v4.102.0
-
-GET /unified/accounts接口, 返回值增加is_all_collateral(是否所有币种均作为保证金)、balances下新增字段enabled_collateral(币种开启作为保证金)
-新增 POST /unified/collateral_currencies 接口,跨币种下可设置抵押币种
-v4.101.9
-
-新增 GET /futures/{settle}/risk_limit_table 接口,根据table_id查询风险限额梯度表
-合约账户模型新增 enable_tiered_mm 字段,支持梯度式维持保证金计算
-持仓模型新增 risk_limit_table(风险限额表)和 average_maintenance_rate(平均维持保证金率)字段,增强风险管理
-合约风险限额梯度新增 deduction 字段,用于维持保证金速算扣减额
-新增模型:FuturesRiskLimitTier(风险限额梯度档位)和 FuturesRiskLimitTierList(风险限额梯度表列表)
-优化 POST /earn/staking/swap 接口响应结构,增强兑换订单详情信息
-v4.100.0
-
-新增alpha账户查询和账户流水查询功能
-优化alpha API币种和ticker查询接口描述,参数使用说明
-新增 GET /earn/staking/coins 接口,查询链上赚币币种
-新增 POST /earn/staking/swap 接口,链上赚币兑换
-经纪商佣金和交易API新增 sub_broker_info 子经纪商信息对象字段
-v4.99.0
-
-GET /spot/accounts 接口, 返回值增加refresh_time字段
-移除 PUT /earn/uni/interest_reinvest 接口
-v4.98.0
-
-新增 /earn/uni/rate 接口, 币种预估年化利率
-GET /spot/currency_pairs、GET /spot/currency_pairs/{currency_pair}接口, 返回值增加delisting_time、trade_url 字段
-v4.97.0
-
-新增 GET /unified/batch_borrowable 接口, 批量查询统一账户最多可借
-GET /spot/candlesticks 接口, interval支持1s粒度
-新增 GET /earn/uni/chart 接口, 余币宝币种年化走势图
-新增 POST /futures/{settle}/positions/cross_mode 接口, 切换全逐仓模式
-v4.96.0
-
-GET /futures/{settle}/accounts 接口, 返回值新增cross_margin_balance,cross_mmr,cross_imr字段
-v4.95.0
-
-GET /spot/account_book 接口, 查询参数新增 code 字段,返回值增加 code 字段
-新增 GET /unified/transferables 接口, 批量查询统一账户最多可转出
-新增 GET /margin/user/loan_margin_tiers 接口, 查询当前市场下用户自身杠杆借贷梯度
-新增 GET /margin/loan_margin_tiers 接口, 查询当前市场杠杆借贷梯度
-新增 POST /margin/leverage/user_market_setting 接口, 设置用户市场杠杆倍数
-新增 GET /margin/user/account 接口, 查询用户逐仓杠杆账户列表
-v4.94.0
-
-新增 GET /unified/currencies 接口, 统一账户支持的借贷币种列表
-GET /unified/accounts 接口, 查询参数新增 sub_uid 字段
-v4.93.0
-
-GET /earn/dual/investment_plan 接口, 查询参数新增 plan_id 字段
-GET /earn/dual/orders 接口, 查询参数新增 from、to、page、limit 字段;
-GET /earn/dual/orders 接口, 返回值增加 text 字段
-POST /earn/dual/orders 接口, 返回值增加 text 字段
-新增 GET /earn/staking/eth2/rate_records 接口, GTETH历史收益率查询
-v4.92.1
-
-2025-02-27
-
-GET /spot/currencies 接口,返回值增加 chains 字段
-GET /spot/currencies/{currency} 接口,返回值增加 chains 字段
-GET /spot/currencies 接口,返回值废弃 withdraw_disabled、withdraw_delayed、deposit_disabled 字段
-GET /spot/currencies/{currency} 接口,返回值废弃 withdraw_disabled、withdraw_delayed、deposit_disabled 字段
-v4.92.0
-
-2025-02-24
-
-GET /spot/currencies 接口,返回值增加 name 字段
-GET /spot/currency_pairs 接口,返回值增加 base_name、quote_name 字段
-GET /spot/price_orders 接口, 查询参数新增 unified 类型
-GET /unified/accounts 接口, 查询参数新增 sub_uid 字段
-v4.91.0
-
-2025-02-10
-
-2025-04-01 之后我们将移除以下接口,请尽快迁移至新接口
-
-v4.90.0
-
-2025-01-20
-
-GET /wallet/push 接口, 查询参数新增transaction_type
-新增 GET /rebate/user/sub_relation 接口, 查询指定用户是否在体系内
-GET /futures/{settle}/liq_orders 接口, 返回值新增order_size字段
-GET /spot/currency_pairs 接口,返回值增加 type 字段
-v4.88.0
-
-2024-12-24
-
-新增 GET /spot/insurance_history 接口, 查询现货保险基金历史数据
-GET /unified/accounts 接口,返回值增加 cross_balance、iso_balance、im、mm、imr、mmr、margin_balance、available_margin
-PUT /unified/unified_mode 接口,新增单币种保证金模式
-v4.87.0
-
-新增 GET /unified/history_loan_rate 接口, 获取历史借币利率
-v4.86.0
-
-2024-12-02
-
-新增 GET /wallet/order_status 划转状态查询
-GET /futures/{settle}/positions 接口,返回值增加 update_id
-v4.85.0
-
-2024-11-11
-
-POST /futures/{settle}/orders、POST /spot/batch_order 接口,请求头新增 x-gate-exptime字段
-POST /futures/{settle}/dual_mode 接口,返回增加 cross_order_margin、cross_initial_margin、cross_maintenance_margin、cross_unrealised_pnl、cross_available、isolated_position_margin 字段
-v4.84.0
-
-2024-11-04
-
-新增 GET /loan/multi_collateral/current_rate 接口, 查询币种活期利率
-GET /spot/tickers 接口, 返回值增加 lowest_size、highest_size 字段
-POST /earn/dual/orders 接口, 请求体新增 amount 字段
-v4.83.0
-
-2024-10-28
-
-新增 GET /unified/leverage/user_currency_config 接口, 查询用户最大、最小可设置币种杠杆倍数
-新增 GET /unified/leverage/user_currency_setting 接口, 获取用户币种杠杆倍数
-新增 POST /unified/leverage/user_currency_setting 接口, 设置币种杠杆倍数
-GET /futures/{settle}/account_book 接口,返回值增加 id 字段
-GET /unified/currency_discount_tiers 接口,返回值增加 leverage 字段
-v4.82.0
-
-2024-10-14
-
-新增 GET /account/rate_limit 接口, 获取用户限流信息. 详情请见成交比率限频
-GET /account/detail 接口, 返回值增加 copy_trading_role 字段
-v4.81.0
-
-2024-09-30
-
-新增 POST /options/countdown_cancel_all 接口, 倒计时取消订单
-GET /wallet/push 接口, 返回值增加 message 字段
-GET /futures/{settle}/funding_rate 接口, 新增 from、to 查询字段
-POST /earn/dual/orders 接口, 返回值增加 is_max 字段
-v4.80.0
-
-2024-09-09
-
-新增 GET /options/mmp 接口, MMP查询
-新增 POST /options/mmp 接口, MMP设置
-新增 POST /options/mmp/reset 接口, MMP重置
-GET /wallet/withdrawals接口, 返回值增加 block_number 字段
-v4.79.0
-
-2024-09-02
-
-GET /unified/interest_records 接口,新增 from、to 查询字段
-GET /unified/unified_mode 接口,返回值增加 options 字段
-PUT /unified/unified_mode 接口,新增 options 字段
-v4.78.0
-
-2024-08-19
-
-新增 GET /wallet/push 接口, 获取记录
-新增 POST /withdrawals/push 接口, 现货主账号之间划转,划转双方不可为子账号
-新增 GET /futures/{settle}/batch_amend_orders 接口, 批量修改指定 ID 的订单
-GET /futures/{settle}/my_trades 接口, 返回增加 close_size 字段
-POST /wallet/transfers 接口, 返回增加 tx_id 字段
-v4.77.0
-
-2024-08-05
-
-新增 GET /sub_accounts/unified_mode 接口,获取子帐号模式
-GET /rebate/broker/commission_history 接口,新增 from、to 查询字段
-GET /rebate/broker/transaction_history 接口,新增 from、to 查询字段
-v4.76.0
-
-2024-07-22
-
-新增 GET /rebate/partner/sub_list 接口,伙人下级列表
-GET /flash_swap/currency_pairs 接口,新增 page、limit 查询字段
-PATCH /spot/orders/{order_id} 接口,新增 order_id、currency_pair、account 字段
-DELETE /spot/orders/{order_id} 接口,新增 order_id、currency_pair、account 字段
-v4.75.1
-
-2024-07-08
-
-新增 GET /delivery/{settle}/risk_limit_tiers 接口,查询风险限额等级
-新增 GET /rebate/partner/transaction_history 接口,合伙人获取推荐用户的交易记录
-GET /unified/loan_records 接口,返回值增加 borrow_type 字段
-GET /futures/{settle}/position_close 接口,返回值增加 accum_size 字段
-v4.75.0
-
-2024-06-24
-
-新增 GET /account/debit_fee 接口,查询GT抵扣配置
-新增 POST /account/debit_fee 接口,设定GT抵扣
-v4.74.1
-
-2024-06-11
-
-针对移动端可视区域DOM优化
-v4.74.0
-
-2024-05-29
-
-新增 GET /unified/loan_margin_tiers 接口, 查询统一账户借贷梯度保证金
-v4.73.0
-
-2024-05-27
-
-POST /wallet/small_balance接口,新增 is_all 字段
-POST /spot/cancel_batch_orders接口,返回值增加 text字段
-GET /unified/accounts接口,返回值增加 funding、funding_version、use_funding字段
-v4.72.0
-
-2024-05-13
-
-GET /sub_accounts/{user_id}/keys接口,返回值增加 last_access字段
-GET /futures/{settle}/risk_limit_tiers接口,返回值增加 contract字段
-v4.71.0
-
-2024-04-23
-
-GET /wallet/saved_address接口,新增 page 查询字段
-新增 GET /api/v4/rebate/user/info 接口, 获取用户返佣信息
-新增 POST /unified/portfolio_calculator 接口,组合保证金计算器计算
-新增 GET /unified/risk_units 接口, 获取用户风险单元详情
-新增 PUT /unified/unified_mode 接口, 设置统一账户模式
-新增 GET /unified/unified_mode 接口, 查询统一账户模式
-v4.70.0
-
-2024-04-08
-
-GET /futures/{settle}/positions接口,返回值增加 pnl_pnl、pnl_fund、pnl_fee字段
-GET /futures/{settle}/position_close接口,返回值增加 pnl_pnl、pnl_fund、pnl_fee字段
-v4.69.0
-
-2024-03-25
-
-POST /delivery/{settle}/price_orders接口,返回值增加 text 字段
-v4.68.0
-
-2024-03-18
-
-新增 GET /unified/currency_discount_tiers 接口,查询统一账户梯度式discount
-GET /unified/loans接口,新增 type 查询字段,返回值增加 type 字段
-GET /unified/interest_records接口,新增 type 查询字段,返回值增加 type 字段
-v4.67.0
-
-2024-03-11
-
-POST /spot/orders,POST /spot/batch_orders接口,返回值增加 filled_amount 字段
-限频规则中,钱包提现接口限速描述,由10r/10s更正为1r/3s(并无修改原本限流行为)
-v4.66.1
-
-2024-02-19
-
-新增 GET /wallet/small_balance 接口,获取可兑换的小额币种清单
-新增 GET /wallet/small_balance_history 接口,获取可兑换的小额币种历史纪录
-新增 GET /unified/estimate_rate 接口,查询统一账户的预估利率
-v4.65.0
-
-2024-01-29
-
-GET /spot/batch_fee 接口,返回值增加 debit_fee 字段
-DELETE /account/stp_groups/{stp_id}/users 接口,新增 user_id 请求字段
-现货API下单增加异步支持模式,ACK,RESULT,FULL,详情请见SPOT API
-v4.64.0
-
-2024-01-22
-
-GET /loan/multi_collateral/orders 接口,新增 order_type 查询字段
-GET /loan/multi_collateral/orders 接口,返回值增加 order_type,fixed_type,fixed_rate,expire_time,auto_renew,auto_repay 字段
-GET /loan/multi_collateral/repay 接口,返回值增加before_ltv,after_ltv 字段
-新增 GET /loan/multi_collateral/fixed_rate 接口,查询币种7日固定利率和30日固定利率
-GET /wallet/total_balance 接口,返回值增加unrealised_pnl,borrowed 字段
-v4.63.0
-
-2024-01-15
-
-GET /wallet/currency_chains 接口,返回值增加 decimal 字段
-新增 GET /futures/{settle}/risk_limit_tiers 接口,查询风险限额等级
-v4.62.0
-
-2024-01-02
-
-新增 POST /futures/{settle}/batch_cancel_orders 接口,用户可批量撤销订单
-新增多币质押API (/loan/multi_collateral/**)
-v4.61.0
-
-2023-12-18
-
-GET /rebate/broker/commission_history 和 GET /rebate/broker/commission_history 接口,新增经纪商获取返佣记录
-v4.60.0
-
-2023-12-01
-
-新的 Unified API 已经上线, 旧的 /portfoli/* 接口已被弃用 (2023-12-31 移除)
-新增理财产品 API (/earn/**)
-GET /futures/{settle}/account_book 接口,返回值增加 trade_id 字段
-v4.59.0
-
-2023-11-22
-
-GET /futures/{settle}/contracts 接口,返回值增加 funding_cap_ratio 字段
-GET /delivery/{settle}/account_book 接口,返回值增加 contract 字段
-GET /wallet/withdraw_status 接口,返回值增加 withdraw_percent_on_chains 字段
-GET /portfolio/accounts 接口,返回值增加 leverage 字段
-v4.58.0
-
-2023-11-03
-
-GET /account/detail 接口, 返回值新增 tier 字段
-GET /spot/currency_pairs 接口, 返回值新增 max_base_amount、max_quote_amount 字段
-v4.57.0
-
-2023-10-20
-
-新增进出网关时间记录,详情参考网关入出站时间
-POST /spot/orders 接口,新增支持保证金帐户类型
-GET /spot/trades 接口,返回值新增 sequence_id 字段
-GET /spot/account_book 接口,返回值新增 text 字段
-GET /spot/my_trades 接口,返回值新增 text 字段
-新增 POST /spot/amend_batch_orders 接口,用户可以批量修改订单
-新增 PUT /earn/uni/interest_reinvest 接口,用户可以设置利息复投开关
-GET /portfolio/spot/orders、 GET /portfolio/spot/orders、GET /portfolio/spot/orders/{order_id}、DELETE /portfolio/spot/orders/{order_id} and PATCH /portfolio/spot/orders/{order_id} 这些接口将被弃用, 我们预计在十月底移除这些接口的支持, 用户可以转用 /spot/orders 相关接口来替代
-v4.56.0
-
-2023-09-25
-
-GET /portfolio/loan_records 接口,新增 repayment_type 字段
-GET /futures/{settle}/positions 接口, 请求参数新增 holding 字段
-GET /futures/{settle}/my_trades_timerange 接口, 请求参数新增 role 字段
-GET /futures/{settle}/position_close 接口, 请求参数新增 side and pnl 字段
-v4.55.0
-
-2023-09-12
-
-新增 POST /portfolio/account_mode 接口,新增模式切换
-v4.54.0
-
-2023-08-28
-
-GET /wallet/currency_chains 接口,新增 contract_address 字段
-GET /portfolio/spot/currency_pairs 与 GET /portfolio/spot/currency_pairs/{currency_pair},新增查询保证金现货市场列表
-v4.53.0
-
-2023-08-14
-
-DELETE /account/stp_groups/{stp_id}/users,新增删除 STP Group 用户接口
-v4.52.0
-
-2023-08-07
-
-新增抵押借币相关 API
-v4.51.0
-
-2023-07-29
-
-调整优化资产流水类型
-GET /account/detail 接口,新增 mode 字段
-v4.50.0
-
-2023-07-14
-
-新增保证金账户体系相关的API,目前服务只对白名单用户开放,有兴趣的用户可以聯繫機構部門
-新增 GET /flash_swap/currency_pairs 接口,查询支持闪兑的所有交易对列表
-v4.49.0
-
-2023-07-03
-
-新增新版限频规则 ,新版预计于 2023-07-10 (utc+8) 开始生效
-GET /futures/{settle}/orders接口,调整请求字段 contract 改为非必填
-v4.48.0
-
-2023-06-16
-
-GET /wallet/sub_account_transfers接口,新增 client_order_id 请求字段
-v4.47.0
-
-2023-05-23
-
-GET /margin/uni/estimate_rate,新增逐仓借贷利率查询接口
-GET /futures/{settle}/orders_timerange,新增查询合约历史订单列表(时间区间)接口
-GET /options/positions/{contract}接口,新增 underlying、underlying_price、mark_iv、delta、gamma、vega、theta 等字段
-新增 STP Group 管理 API 接口
-v4.46.0
-
-2023-05-08
-
-GET /spot/account_book,新增查询现货账户变动历史接口
-GET /futures/{settle}/fee,新增查询合约市场交易费率接口
-v4.45.0
-
-2023-04-21
-
-逐仓借贷迁移到余币宝,详细资讯可参考逐仓迁移说明
-POST /futures/{settle}/batch_orders 接口,新增 STP 功能
-v4.44.0
-
-2023-04-07
-
-新增 ORDER_BOOK_NOT_FOUND、FAILED_RETRIEVE_ASSETS 错误信息
-v4.43.0
-
-2023-03-27
-
-现货下单接口,新增 Self-Trade Prevention 功能,详细资讯可参考STP介绍
-GET /account/detail,新增查询 API Key 的 IP 白名单接口
-PATCH /spot/orders/{order_id} 接口,新增 amend_text 字段
-v4.42.0
-
-2023-03-13
-
-新增余币宝接口
-合约下单接口,新增 Self-Trade Prevention 功能,详细资讯可参考STP介绍
-POST /wallet/sub_account_transfers 接口,新增 交割合约账户 类型支持
-v4.40.0
-
-2023-02-24
-
-GET /futures/{settle}/candlesticks 接口,新增 sum 字段
-GET /futures/{settle}/auto_deleverages 接口,新增查询ADL自动减仓订单信息
-v4.39.0
-
-2023-02-09
-
-GET /spot/batch_fee 接口,新增批量查询账户费率接口
-GET /futures/{settle}/contracts 接口,新增 enable_bonus、enable_credit 字段
-v4.38.0
-
-2023-02-04
-
-GET /futures/{settle}/my_trades_timerange 接口,新增时间范围查询合約成交记录接口
-POST /withdrawals 接口,新增 withdraw_order_id 字段
-v4.37.0
-
-2023-01-20
-
-新增查询反佣相关接口
-v4.36.0
-
-2022-12-23
-
-POST /spot/orders 和 POST /spot/batch_orders 接口,下单的时候 iceberg 字段不再支持全部订单隐藏
-v4.35.0
-
-2022-12-09
-
-GET /spot/orders 接口, 新增订单平均价格字段
-PATCH /spot/orders/{order_id} 接口, 新增订单修改单
-POST /spot/batch_orders 接口, 新增现货市价单类型
-v4.34.0
-
-2022-11-25
-
-POST /spot/orders 接口, 现货下单增加市价单
-v4.33.0
-
-2022-11-11
-
-K 线图接口 GET /futures/{settle}/premium_index
-创建子帐号的时候可以指定密码与 Eamil
-v4.32.0
-
-2022-10-28
-
-优化期权API文档
-v4.31.0
-
-2022-10-14
-
-POST /wallet/sub_account_to_sub_account 子帐号划转接口,新增合约与全仓杠杆划转
-v4.30.0
-
-2022-09-23
-
-新增管理子帐号 API Key 接口
-新增子帐号冻结与解冻接口
-POST /wallet/sub_account_to_sub_account 接口,新增子帐号与子帐号划转
-v4.29.0
-
-2022-09-09
-
-新增创建、查询子帐号功能
-GET /wallet/fee 接口,新增 settle 查询字段
-期权订单新增 refr 字段
-创建 API Key 数量上限调整至 20
-v4.28.0
-
-2022-08-12
-
-GET /futures/{settle}/trades 接口,新增 offset 查询字段
-新增现货与合约的定时取消订单接口
-v4.27.0
-
-2022-07-29
-
-新增 X-Client-Request-Id 请求 ID header,可以用来追踪请求
-新增合约批量下单接口,POST /futures/{settle}/batch_orders
-新增合约交易下单FOK订单类型
-v4.26.0
-
-2022-07-15
-
-现货自动单支持统一帐户
-新增 GET /wallet/saved_address 接口,获取提币白名单地址
-POST /wallet/transfers 接口,支援操作单号返回
-新增 GET /wallet/sub_account_cross_margin_balances 接口,查询子账号全仓杠杆账户余额信息
-GET /margin/currency_pairs 接口、新增 status 字段
-v4.25.1
-
-2022-07-06
-
-新增 GET /spot/time 获取服务器当前时间接口
-获取交易对 ticker 信息 GET /spot/tickers,新增 change_utc0, change_utc8 字段
-新增 GET /options/my_settlements 查询期权个人结算记录接口
-v4.25.0
-
-2022-06-24
-
-支持统一帐户 API
-全仓账户增加多个返回字段,详细请查看接口描述
-现货交易增加接口POST /spot/cross_liquidate_orders,处理全仓币种禁用时平仓买入下单
-获取合约账号接口新增 bonus 理财金字段和 history 累计统计数据字段
-合约个人成交记录新增 text 订单的自定义信息,fee 成交手续费,point_fee成交点卡手续费等字段
-订正撤销单个自动单名称
-POST /wallet/sub_account_transfers 支持划转到全仓杠杆账户
-v4.24.0
-
-2022-05-20
-
-新增 /flash_swap 闪兑 API ,支持直接通过 API 方式进行闪兑操作,接口组关联现货权限
-钱包新增 GET /wallet/sub_account_margin_balances , GET /wallet/sub_account_futures_balances 接口,方便主账号查询子账号的逐仓杠杆账户和永续合约账户的余额信息
-永续合约新增 API GET /futures/{settle}/index_constituents/{index} 查询指数来源信息
-修复合约自动订单 FuturesPriceTriggeredOrder 缺少 order_type 等字段的定义
-v4.23.4
-
-2022-04-25
-
-现货 K 线查询支持 30d 粒度
-v4.23.3
-
-2022-04-01
-
-现货 K 线增加基础货币成交量返回
-现货币种信息返回增加该币所在链的信息
-钱包接口 GET /wallet/currency_chains 增加币种的充提状态返回
-永续合约双仓模式下增加缺失的全仓杠杆 cross_leverage_limit 参数
-永续、交割合约查询 K 线新增多个时间粒度的支持
-v4.23.2
-
-2022-01-21
-
-提现充值历史增加 fee 字段返回
-现货 Currency 币种模型增加固定费率
-v4.23.1
-
-2021-12-23
-
-现货下单 time_in_force 增加新类型 FOK
-新增错误代码 FOK_NOT_FILL
-v4.23.0
-
-2021-12-09
-
-新增期权 API
-新增详细的限速规则说明
-新增 GET /wallet/currency_chains 查询币种支持的链
-提现充值历史增加新的 status 可选值
-v4.22.4
-
-2021-11-01
-
-SpotPriceTriggeredOrder 字段 ctime 和 ftime 更正为 int64
-v4.22.3
-
-2021-10-27
-
-GET /spot/trades 支持指定 from 和 to 按时间范围筛选的查询
-v4.22.2
-
-2021-09-29
-
-提现充值记录新增 status 字段的可选值
-合约下单新增 auto_size 只写字段用于双向持仓模式的平仓操作
-v4.22.1
-
-2021-09-07
-
-新增钱包接口 GET /wallet/total_balance 获取用户总资产
-逐仓杠杆账户返回增加locked 和 risk 字段
-逐仓和全仓杠杆借入支持输入自定义 text
-v4.22.0
-
-2021-08-13
-
-交割合约支持 BTC 结算
-现货 API GET /spot/orders 和 GET /spot/my_trades 支持按时间范围筛选
-逐仓和全仓支持查询用户最大借入额度
-v4.21.6
-
-2021-08-12
-
-修复 GET /wallet/deposit_address 地址链字段错误名称
-v4.21.5
-
-2021-06-30
-
-针对已结束的单子, GET /spot/orders, GET /spot/orders/{order_id} 以及 GET /spot/my_trades 接口可以不用指定 currency_pair 参数
-GET /wallet/withdraw_status 返回增加多链的固定提现手续费返回
-新增 GET /margin/transferable API 查询逐仓和全仓账户允许的最大转出额度
-合约平仓历史 API 新增 from 和 to 的时间范围查询参数
-v4.21.4
-
-2021-06-23
-
-逐仓账户历史 GET /margin/account_book 返回增加毫秒时间戳
-v4.21.3
-
-2021-06-17
-
-现货、合约深度增加时间戳返回
-v4.21.2
-
-2021-06-07
-
-合约 API 新增对全仓杠杆调整的支持
-新增 /margin/cross 全仓杠杆 API
-新增现货下单对全仓杠杆账户的支持
-逐仓杠杆账户查询返回新增账户未还利息
-现货订单信息新增 create_time_ms 和 update_time_ms 毫秒时间返回
-新增取消提现接口 DELETE /withdrawals/{withdrawal_id}
-v4.20.1
-
-2021-04-14
-
-更新文档部分链接
-v4.20.0
-
-2021-03-25
-
-增加现货自动订单接口组 /spot/price_orders
-v4.19.6
-
-2021-03-22
-
-现货交易对查询增加开盘时间返回
-v4.19.5
-
-2021-03-18
-
-指定订单 ID 的现货、永续合约操作支持使用用户自定义 ID(只在订单创建后的 30 分钟内有效)。
-v4.19.4
-
-2021-03-10
-
-/wallet/sub_account_transfers 接口支持转账到子账户的合约账户
-v4.19.3
-
-2021-03-04
-
-新增杠杆借贷自动还款设置和查询接口 /margin/auto_repay
-/wallet/deposit_address 接口新增 multichain_address 字段,返回某些币种的多充值地址
-优化部分文档内容
-v4.19.2
-
-2021-03-01
-
-新增 /wallet/fee 接口用于查询交易费率,原有 /spot/fee 接口废弃
-提现操作增加 chain 字段
-合约深度查询 /futures/{settle}/order_book 增加 with_id 字段的说明,返回内容增加深度 ID 的说明
-合约个人平仓历史查询 /futures/{settle}/position_close 增加 offset 参数,用于翻页获取历史平仓记录
-增加合约价值的计算方法说明,具体参考 Contract 模型的描述
-修复合约统计数据字段类型错误
-v4.18.4
-
-2021-01-22
-
-现货 Trade 模型新增 create_time_ms 字段
-ETF 交易对 Ticker 增加净值等相关信息返回
-v4.18.1
-
-2021-01-07
-
-现货下单新增冰山委托支持
-修复 /futures/{settle}/contract_stats 返回数据的错误字段类型
-v4.18.0
-
-2020-12-21
-
-现货新增 /spot/currencies 和 /spot/currencies/{currency} 查询币种信息
-合约 ContractStat 返回新增 top_lsr_account 和 top_lsr_size 等多个字段
-v4.17.1
-
-2020-12-16
-
-/spot/order_book 接口 limit 字段最大值增加到 100
-v4.17.0
-
-2020-12-15
-
-新增子账号余额查询接口 /wallet/sub_account_balances
-v4.16.1
-
-2020-12-10
-
-修复 Position 模型定义里的错误字段名称 dual_mode 。正确应该是 mode
-v4.16.0
-
-2020-12-09
-
-现货
-
-POST /spot/batch_orders 每个交易对可以创建的 order 数量提高到 10 个
-现货 GET /spot/trades 新增 reverse 参数支持时间逆序查询历史记录
-合约
-
-永续合约新增双仓支持 API ,/futures/{settle}/dual_mode 接口设置是否开启双仓。 双仓相关的仓位操作参照 /futures/{settle}/dual_comp/positions 接口组
-永续合约账户返回新增 in_dual_mode ,仓位返回新增 dual_mode
-永续合约新增 /futures/{settle}/liq_orders 支持查询市场强平记录
-v4.15.5
-
-2020-11-04
-
-新增 API /futures/{settle}/contract_stats 获取合约统计信息
-新增 API /margin/{currency_pair} 获取单个杠杆交易对详情
-v4.15.4
-
-2020-09-01
-
-GET /spot/fee 接口返回新增 point_type 字段
-新增 API GET /wallet/withdraw_status
-新增了 C# SDK 入口
-v4.15.2
-
-2020-08-12
-
-新增 GET /spot/fee 获取个人现货交易费率
-v4.15.1
-
-2020-08-04
-
-新增获取现货市场所有当前委托 GET /spot/open_orders
-新增杠杆账户余额变更历史 GET /margin/account_book
-v4.14.1
-
-2020-07-08
-
-订单里的 text 字段最大允许长度提高到了 28 个字节(不包括前缀)
-v4.14.0
-
-2020-07-06
-
-交割合约引擎 API /delivery 上线
-v4.13.1
-
-2020-06-28
-
-新增 GET /wallet/sub_account_transfers 接口查询主子账号划转历史
-v4.13.0
-
-2020-05-20
-
-增加了对提现操作的支持,详情关注 POST /withdrawals 接口和“认证”一节
-账户划转 POST /wallet/transfers 支持现货到合约了。
-钱包接口新增了提现充值历史记录查询
-合约订单和个人成交列表支持传入 offset 参数
-合约 Contract 模型添加新字段 in_delisting
-v4.12.0
-
-2020-04-08
-
-升级 APIv4 的 Key ,不再按功能独立 Key,每个 Key 都可以独立配置多个功能的权限, 详细说明参考 “关于 APIv4 Key 升级” 一节
-新增接口 POST /wallet/sub_account_transfers 支持主子账号余额划转
-GET /spot/candlesticks 增加请求参数 from 和 to ,方便获取历史数据
-v4.11.2
-
-2020-03-29
-
-Order 模型增加字段 filled_total 替换命名容易引起误解的 fill_price
-添加新的错误码标识 POC_FILL_IMMEDIATELY
-v4.11.1
-
-2020-03-23
-
-个人成交记录 GET /spot/my_trades 返回增加 role 交易角色信息
-修复查询币币理财账户 GET /margin/funding_accounts 缺少未使用过理财的币种的问题
-v4.11.0
-
-2020-03-20
-
-现货下单支持 GT 抵扣费率折扣
-现货下单 Time in force 支持传入 poc
-v4.10.1
-
-2020-02-24
-
-现货交易对新增字段 trade_status
-v4.10.0
-
-2020-02-17
-
-杠杆下单支持传入 auto_borrow 字段(只写),在余额不足时由系统自动借入不足部分
-增加指定订单 ID 的批量撤单接口 POST /spot/cancel_batch_orders
-补充“错误处理”和“与 APIv2 的区别”文档
-v4.9.1
-
-2020-01-07
-
-Order 和 BatchOrder 新增订单最近修改时间、成交费率的返回
-GET /spot/my_trades 增加成交费率返回
-v4.9.0
-
-2019-12-17
-
-GET /futures/{settle}/trades 不再支持 last_id 参数,改用 from 和 to 来获取历史成交
-v4.8.2
-
-2019-12-02
-
-新增 /spot/batch_orders 支持现货和杠杆的批量下单操作
-杠杆还款产生的手续费率支持用户等级折扣
-Loan 模型里增加了 fee_rate 字段标识杠杆借出单的手续费率,orig_id 标识续借单的原始借出单 ID
-v4.8.1
-
-2019-11-27
-
-修复 GET /futures/{settle}/positions 文档和代码示例缺少 settle 字段的说明和使用
-v4.8.0
-
-2019-11-07
-
-合约 API 支持以 USDT 结算
-原有的以 /futures 为前缀的所有接口前缀统一调整为 /futures/{settle} ,以支持基于多种结算货币的合约操作。
-/futures/{settle}/accounts 返回的账户信息里 currency 增加 USDT 的返回 volume_24h_settle 字段,取代原有 volume_24h_btc 和 volume_24h_usd 的使用。 后两个字段为了兼容依然保留,但是新的操作不推荐继续使用。
-将 /futures 替换成 /futures/usdt 就可以使用 USDT 结算的合约操作, 例如 GET /futures/usdt/accounts 能够获取 USDT 的合约账户,而 GET /futures/btc/accounts 则是用来获取 BTC 的合约账户。
-
-为了保持兼容, 原有的 GET /futures/xxx 的 API 都会默认为 BTC GET /futures/btc/xxx 。如 GET /futures/accounts 会被服务默认按 GET /futures/btc/accounts 请求来处理
-
-v4.7.3
-
-2019-07-18
-
-现货、合约下单增加 text ,支持用户自定义信息
-v4.6.3
-
-2019-06-11
-
-合约账户和仓位信息里增加点卡相关信息
-v4.7.2
-
-2019-05-29
-
-理财借出 Loan 的 rate 字段调整为非必选
-v4.7.1
-
-2019-04-17
-
-新增 wallet v4 API ,目前仅支持现货与杠杆账户转账操作
-GET /margin/loans 接口支持按 rate 排序,支持可选 currency_pair 输入
-修复各种文档问题
-v4.6.2
-
-2019-04-24
-
-修复合约价格单文档覆盖了普通合约单接口 GET /futures/orders/{order_id} 和 DELETE /futures/orders/{order_id} 的文档
-v4.6.1
-
-2019-04-02
-
-合约 Ticker 返回新增字段 high_24h 、 low_24h 和 funding_rate_indicative
-v4.6.0
-
-2019-03-21
-
-只影响 SDK
-
-修改合约相关的下单函数名,防止在 Go SDK 中与现货下单冲突
-修复验签时没有对请求参数做 decode 的问题
-v4.5.2
-
-2019-03-14
-
-/spot/order_book 的参数 currency_pair 应为必选
-优化代码示例
-v4.5.1
-
-2019-03-11
-
-修复缺少 URL 参数的说明
-v4.5.0
-
-为了避免引起版本混乱,APIv4 此后的版本统一以 4 作为大版本号开头(包括文档和 SDK)
-
-2019-03-05
-
-新增现货 v4 API,在原有 API 基础之上提供更多功能
-新增杠杆 v4 API,提供杠杆借贷功能;杠杆交易API 复用现货 v4 交易API
-提供合约止盈止损自动单 API 支持,详情见 /futures/price_orders 一组接口
-实盘交易统一 APIv4 统一 Base URL 到 https://api.gateio.ws/api/v4
-v1.3.0
-
-2019-02-13
-
-重要更新
-
-base URLs 域名更新为 fx-api.gateio.ws 和 fx-api-testnet.gateio.ws 原有 *.gateio.io 已废弃
-v1.2.1
-
-2019-02-13
-
-合约 Ticker 接口返回增加 volumn_24h_usd 和 volume_24h_btc
-v1.2.0
-
-2019-01-17
-
-新增 GET /futures/contracts/{contract} 查询单个合约
-新增 GET /futures/positions/{contract} 查询单个合约的仓位
-新增 GET /futures/account_book 查询用户合约账户历史
-Contract 模型新增 config_change_time 字段
-修复各种文档问题
-v1.1.0
-
-2019-01-08
-
-Contract, Position, FuturesOrder 模型增加更多参数
-新增 API GET /futures/position_close 获取平仓记录
-API GET /futures/my_trades 增加可选参数 order_id 支持
-DELETE /futures/orders 和 DELETE /futures/orders/{order_id} 返回状态码从 204 改为 200, 并在请求成功后返回撤销的订单列表
-DELETE /futures/orders/{order_id} 对无效订单不忽略错误,改为返回 404
-POST /futures/orders 支持 POC 和冰山委托
-v1.0.0
-
-2018-12-30
-
-初次发布
-#General
-#匹配机制
-#匹配优先级
-Gate 订单匹配遵循 价格优先 > 时间优先 的原则
-
-假设订单簿情况如下:
-
-匹配优先级
-订单 下单时间 Ask/卖价
-A 10:00 100
-B 10:00 102
-C 10:01 100
-如果 10:02 分 的现价买单 102,最终成交顺序为: A、C、B
-
-#订单生命周期
-发送到匹配引擎的有效订单会立即被接受,并跟已有挂单进行匹配,然后将匹配结果返回给客户端。
-
-匹配结果若是完全执行,则订单结束。若结果是不执行或部分执行,TimeInForce 为 IOC 的订单会立即结束; 其他情况的订单,则被挂在相应价格订单队尾,等待被匹配或者被撤销。
-
-#数据中心
-Gate 数据中心位于 AWS 日本东京 (ap-northeast-1) 地区。
-
-#接口概览
-接口概览
-接口分类 分类链接 概述
-host + /api/v4/spot/* 现货交易 包含币种状态、行情信息、下单、成交记录等功能
-host + /api/v4/margin/* 杠杆交易 杠杆账户管理、借贷、还款等
-host + /api/v4/futures/* 永续合约交易 永续合约账户管理、行情信息、下单、成交记录等功能
-host + /api/v4/delivery/* 交割合约交易 交割合约账户管理、行情信息、下单、成交记录等功能
-host + /api/v4/options/* 期权交易 期权账户管理、行情信息、下单、成交记录等功能
-host + /api/v4/wallet/* 钱包管理 充提记录、查询余额、资金划转等
-host + /api/v4/withdrawals/* 提现 数字货币提现
-#逐仓迁移说明
-平台于 2023 年 4 月 13 日 14:00(UTC+8)到 2023 年 4 月 23 日 14:00(UTC+8)期间陆续对币币理财市场中未被借贷的资产进行系统自动迁移,迁移至余币宝市场,同时也会对已经被借贷出去的资产进行取消自动放贷处理,迁移完成后您可到余币宝市场中,查看您的理财详情。在此期间将暂停通过币币理财借出资金,您也可以手动将资产从币币理财转到余币宝市场,提前获得理财收益。
-自动迁移后老版本的借贷接口将被弃用,新版借贷使用/margin/uni接口组,详细的接口迁移可以参考下表
-
-逐仓杠杆账户相关接口:
-
-逐仓迁移说明
-接口名称 路径 接口是否下线 新路径
-杠杆账户列表 GET /margin/accounts 否 -
-查询杠杆账户变动历史 GET /margin/account_book 否 -
-理财账户列表 GET /margin/funding_accounts 否 -
-修改用户自动还款设置 POST /margin/auto_repay 否 -
-查询用户自动还款设置 GET /margin/auto_repay 否 -
-逐仓杠杆允许的最大转出 GET /margin/transferable 否 -
-逐仓杠杆借贷相关接口(迁移至/margin/uni接口组):
-
-逐仓迁移说明
-接口名称 路径 接口是否下线 新路径
-查询支持杠杆交易的所有交易对 GET /margin/currency_pairs 是 GET /margin/uni/currency_pairs
-查询单个杠杆交易对 GET /margin/currency_pairs/{currency_pair} 是 GET /margin/uni/currency_pairs/{currency_pair}
-借入或借出 POST /margin/loans 是 POST /margin/uni/loans
-查询借贷订单详情 GET /margin/loans/{loan_id} 是 -
-查询借贷订单列表 GET /margin/loans 是 GET /margin/uni/loans
-归还借贷 POST /margin/loans/{loan_id}/repayment 是 POST /margin/uni/loans
-查询借贷归还记录 GET /margin/loans/{loan_id}/repayment 是 GET /margin/uni/loan_records
-逐仓杠杆用户最多可借入 GET /margin/borrowable 是 GET /margin/uni/borrowable
-查询扣息记录 - - GET /margin/uni/interest_records
-理财相关接口(迁移至/earn/uni接口组):
-
-逐仓迁移说明
-接口名称 路径 接口是否下线 新路径
-查询支持杠杆交易的所有交易对 GET /margin/currency_pairs 是 GET /earn/uni/currencies
-查询单个杠杆交易对 GET /margin/currency_pairs/{currency_pair} 是 GET /earn/uni/currencies/{currency}
-借入或借出 POST /margin/loans 是 POST /earn/uni/lends
-查询借贷订单列表 GET /margin/loans 是 GET /earn/uni/lends
-借出市场的深度 GET /margin/funding_book 是 -
-合并多个借贷订单 POST /margin/merged_loans 是 -
-修改借贷订单 PATCH /margin/loans/{loan_id} 是 PATCH /earn/uni/lends
-撤销借出贷款订单 DELETE /margin/loans/{loan_id} 是 POST /earn/uni/lends
-查看某个借贷订单的借出记录 GET /margin/loan_records 是 GET /earn/uni/lend_records
-查看单个借出记录 GET /margin/loan_records/{loan_record_id} 是 -
-修改单个借出记录 PATCH /margin/loan_records/{loan_record_id} 是 -
-查询用户派息记录 - - GET /earn/uni/interest_records
-#API
-#HTTP 通用格式
-所有读操作都是 GET 方法,只接受请求参数,不读取任何请求体。
-DELETE 方法移除指定资源(如委托),但因为 DELETE 方法也不读取任何请求体, 并不是所有移除操作都是用 DELETE 方法。复杂的移除操作通过 POST 方法配合请求体来实现。
-更新操作使用 POST, PUT 或 PATCH 方法,不同的请求有不同的参数传递方式, 但是他们要么是通过请求体,要么是请求参数,不会二者混用。
-所有操作成功时都会返回 HTTP 状态码 2xx 。401 说明认证有问题。其他 4xx 状态码说明请求无效。 如果是 5xx 错误,则是服务端处理请求时遇上了未知的严重错误,碰到的话请第一时间反馈。
-#时间
-所有时间字段,如果没有额外说明,格式都是秒级的 Unix 时间戳,但是返回的格式可能不同 int64, number 或者 string ),示例值如:
-
-1596531048
-"1596531048"
-1596531048.285
-"1596531048.285"
-最佳方式是按有小数点的 number 去解析 (string 需要实现转换)。 如果不需要高精度, 再强转成整数(或长整形)。上面的 SDK 会对不同格式的时间字段按照相应格式做好反序列化处理。
-
-#网关入出站时间
-每次请求API响应头(response header)中都会包含如下字段:
-
-X-In-Time: API网关接收请求时的时间戳,格式:Unix的时间戳,单位微秒。
-
-X-Out-Time: API网关返回响应时的时间戳,格式:Unix的时间戳,单位微秒
-
-例如:
-
-X-In-Time: 1695715091540163
-X-Out-Time: 1695715091551905
-#分页
-分页的实现有如下两种方式:
-
-page, limit 方式
-limit, offset 方式
-这两种方式里,limit 字段都是用来限制单次请求里列表返回的最大数量。没有特殊说明的情况下, 它的默认值是 100 ,最大允许 1000 。
-
-page 方式类似于网页的翻页,从 1 开始计数。遍历完整列表的方法是使用同一个 limit,每次请求将 page 加 1,直到返回的列表长度小于 limit
-
-offset 方式类似于数据库检索,遍历完整列表的方式是每次累加 limit 到 offset 上, 直到返回的列表长度小于 limit
-
-举例说明,如果订单总数是 201 个。使用 page-limit 方式,请求参数可以按照如下发送:
-
-page=1&limit=100
-page=2&limit=100
-page=3&limit=100
-如果使用 limit-offset 方法,则是:
-
-limit=100&offset=0
-limit=100&offset=100
-limit=100&offset=200
-有一些请求可能会返回额外的分页元数据信息。这些元数据信息都存储在返回头部。以 GET /futures/{settle}/orders 为例,这个请求会在返回头部追加如下分页元数据信息:
-
-X-Pagination-Limit: 请求指定的 limit 参数
-X-Pagination-Offset: 请求指定的 offset 参数
-X-Pagination-Total: 满足条件的所有条目总数
-#限频规则
-限频规则
-市场 入口 限速 依据 包含
-公共接口 公共接口 单个接口 200r/10s IP 深度、K线、交易对信息等
-钱包 私有接口 提现接口(POST /withdrawals) 1r/3s
-提现uid转账接口(POST /withdrawals/push) 1r/10s
-交易账户互转接口 (POST /wallet/transfers) 80r/10s
-主子账号互转 (POST /wallet/sub_account_transfers) 80r/10s
-子账号与子帐号互转 (POST /wallet/sub_account_to_sub_account) 80r/10s
-查询个人账户总额 (GET /wallet/total_balance) 80r/10s
-查询子账号余额信息 (GET /wallet/sub_account_balances) 80r/10s
-查询子账号逐仓杠杆账户余额信息 (GET /wallet/sub_account_margin_balances) 80r/10s
-查询子账号永续合约账户余额信息 (GET /wallet/sub_account_futures_balances) 80r/10s
-查询子账号全仓杠杆账户余额信息 (GET /wallet/sub_account_cross_margin_balances) 80r/10s
-钱包其他单个接口 200r/10s
-UID 提现
-个人账户余额查询
-子账户余额查询
-现货 私有接口 现货批量/单个下单/单个修改接口一共订单数 10r/s (uid+市场)
-现货批量/单个撤单接口一共 200r/s
-现货其他单个接口 200r/10s
-UID 现货下单、撤单
-成交历史、费率查询等
-永续合约 私有接口 合约批量/单个下单/修改单个订单接口一共 100r/s
-合约批量/单个撤单接口一共 200r/s
-永续合约其他单个接口 200r/10s
-UID 合约下单、撤单
-成交历史、费率查询等
-交割合约 私有接口 单个下单接口 500r/10s
-单个撤单接口 500r/10s
-交割其他单个接口 200r/10s
-UID 下单、撤单
-期权合约 私有接口 单个下单接口 200r/s
-单个撤单接口 200r/s
-期权其他单个接口 200r/10s
-UID 下单、撤单
-子账户 私有接口 单个子账户相关接口 80r/10s UID 创建普通子账户
-查询子账户列表
-禁用、启用子账户APIKEY
-保证金 私有接口 借入或还款 15/10s UID 借入或还款(POST /unified/loans)
-其他私有接口 私有接口 单个接口 150r/10s UID 理财、抵押借币等
-限速是每个子账号或主账号单独计算的
-
-限流字段
-
-每次请求API响应头(response header)中都会包含如下字段:
-
-X-Gate-RateLimit-Requests-Remain - 该接口当前时间窗口剩余可用请求数
-X-Gate-RateLimit-Limit - 该接口当前频率限制上限
-X-Gate-RateLimit-Reset-Timestamp - 如果您已超过该接口当前窗口频率限制,该字段表示下个可用时间窗口的时间戳(秒),即什么时候可以恢复访问;如果您未超过该接口当前窗口频率限制,该字段表示返回的是当前服务器时间(秒).
-WebSocket:
-
-现货: 现货批量/单个下单/单个改单一共 10r/s
-合约: 合约批量/单个下单/单个改单/单个撤单/批量撤单s一共 100r/s
-其他:无限制
-每个 IP 最大连接数: ≤ 300
-#成交比率限频
-为提升交易效率,我们决定为成交比率较高的用户实施更为优越的子账户频率限制。该评估将依据过去七天的交易数据,于每日 00:00 UTC 进行计算。请注意,此项规则仅适用于 VIP14 及以上的用户。
-
-#1. 术语介绍
-#1.1 交易产品系数
-为了更为精细化管理不同交易产品对成交比率的影响,我们引入了交易产品系数的概念。这一系数的设定允许我们根据产品的特性调整其对于总体成交量的影响。对于那些系数小于1的产品,它们通常涉及较小的合约规模,因此需要更多的交易指令来达到相同的交易量。通常情况下,所有交易产品都配备了一个默认系数,然而,部分产品根据其特性被赋予了独立的系数。相关产品的具体系数信息,请参考所提供的表格资料。
-
-1.1 交易产品系数
-业务线 基于 独立系数 默认系数
-USDT 永续合约 合约市场 1
-合约市场:
-BTC-USDT
-ETH-USDT 0.4
-现货 现货市场 1
-合约市场:
-BTC-USDT
-ETH-USDT 0.4
-请注意:现货本期暂时不会上线
-
-#1.2 交易量权重定义
-我们会根据市场来波动,评估 maker 和 taker的行为模式,并据此设计 maker 与 taker 的交易量比例权重。此外,我们将定期对这些权重进行评估,并在必要时进行同步调整。
-
-本次 maker交易量占比权重:100%, taker交易量占比权重:90%
-
-#1.3 成交比例计算公式
-系统将在每日 08:00 UTC,依据 00:00 UTC 的数据快照,从子账户成交比率和母账户综合成交比率中选取较高的值,以确定子账户的未来限频。对于独立经纪商,系统将仅考虑其子账户的成交比率。需要注意的是,母账户也会被视作一个“子账户”。
-
-子账户成交比率:该比率的计算方式为(子账户 永续合约Taker 的 USDT 成交量 × 0.9 + 永续合约Maker 的 USDT 成交量 × 1)/(各交易产品的新增和修改请求总数 × 交易产品系数总和)。
-母账户综合成交比率:此比率的计算方式为(母账户的 永续合约Taker USDT 成交量 × 0.9 + 永续合约Maker USDT 成交量 × 1)/(所有子账户的各交易产品新增和修改请求总数 × 交易产品系数总和)。
-#2. 现货下单频率限制规则
-#2.1 现有限频规则
-现货批量/单个下单/单个修改接口一共订单数 10r/s (市场)
-
-同一个UID在不同的市场限速均为10r/s,在不同现货市场的限速相互独立
-#2.2 新增限频规则
-平台将对在短期内频繁进行下单、撤单或修改订单操作,但成交率较低的交易行为实施限速,具体规则内容如下:
-
-1. 统计周期
-
-统计周期:统计最近24小时的数据,每小时进行一次统计。
-2. 请求类型
-
-统计项:统计所有请求,包括下单、撤单和修改订单中成功请求和失败请求(如被动委托成交、资金不足等)。
-3. 限频标准
-
-对下单(POST /spot/orders)和修改订单(PATCH /spot/orders/{order_id})两个API接口进行限速。基于UID降至每10秒不超过10次请求,建议客户保持自己的成交率在0.1以上。
-4. 解锁机制
-
-系统将对用户的交易行为进行动态评估,在每小时一次的检测中,一旦检测到用户策略调整并符合我们的效率标准,将会解除限制。
-说明:
-
-系统每小时统计最近24小时成交率,至少限制一个小时。如果用户在当前小时被限制,按照每个小时统计一次成交率,若当前小时成交率大于阈值时,下一个小时则限制解除。
-#2.3 成交率计算公式
-成交率 = USDT成交金额 / (下单&撤单&修改订单请求数之和)
-
-#3. 合约下单频率限制规则
-3. 合约下单频率限制规则
-合约限频规则
-Tier ratio rate limit (uid)
-Tier 1 [0,1) 100r/s
-Tier 2 [1,3) 150r/s
-Tier 3 [3,5) 200r/s
-Tier 4 [5,10) 250r/s
-Tier 5 [10,20) 300r/s
-Tier 6 [20,50) 350r/s
-Tier 7 >= 50 400r/s
-现货敬请期待
-
-#4. 成交比例详细规则
-面向客户群体:VIP≥ 14
-计算周期:7天
-更新时间:每日08:00 (UTC),系统将根据UTC时间 00:00 的数据,更新成交比例的数据。
-若成交比率和预期限速有所改善,则提升将于 08:00 (UTC) 立即生效。
-但若成交比率下降,则将会立即进行降低限频。
-若用户的VIP等级下降级为 VIP14以下,其限速将降低为最低档位,立即生效。
-若用户的VIP等级上升为VIP14以上,其根据目前所在等级立刻调整。
-若子账户7日交易量低于1,000,000 USDT,则按照母账户的合计成交比率实施限速。
-对于新创建的子账户,创建时将应用最低档位限速,在 T+1 08:00 (UTC) 进行计算,开始应用上述限速规则。
-WebSocket和REST 同时适用该规则
-#5. 示例
-假设用户拥有三个账户,交易永续合约产品 BTC-USDT 和 SOL-USDT 的系数分别为 1 和 0.4。
-
-账户 A(主账户):
-BTC-USDT Maker 交易量为 100 USDT,订单请求数为 10,Taker 交易量为 200 USDT,订单请求数为 20。
-SOL-USDT Maker 交易量为 20 USDT,订单请求数为 15,Taker 交易量为 20 USDT,订单请求数为 20。
-子账户成交比率 = ((100+20)*1 + (200+20)*0.9) / ((10+20) * 1 + (15+20) * 0.4) = 7.23
-账户 B (子账户):
-BTC-USDT Maker 交易量为 200 USDT,订单请求数为 20,Taker 交易量为 200 USDT,订单请求数为 30。
-SOL-USDT Maker 交易量为 20 USDT,订单请求数为 5,Taker 交易量为 30 USDT,订单请求数为 5。
-子账户成交比率 = ((200+20)*1 + (200+30)*0.9) / ((20+30) * 1 + (5+5) * 0.4) = 7.91
-账户 C (子账户):
-BTC-USDT Maker 交易量为 50 USDT,订单请求数为 5,Taker 交易量为 60 USDT,订单请求数为 8。
-SOL-USDT Maker 交易量为 100 USDT,订单请求数为 20,Taker 交易量为 120 USDT,订单请求数为 25。
-子账户成交比率 = ((50+100)*1 + (60+120)*0.9) / ((5+8) * 1 + (20+25) * 0.4) = 10.06
-母账户综合成交比率 = ((100+20+200+20+50+100)*1 + (200+20+200+30+60+120)*0.9) / ((10+20+20+30+5+8)*1 + (15+20+5+5+20+25)*0.4) = 8.19
-账户限频:
-账户 A = max(7.23, 8.19) = 8.19 -> 250r/s
-账户 B = max(7.91, 8.19) = 8.19 -> 250r/s
-账户 C = max(10.06, 8.19) = 10.06 -> 300r/s
-#6. 备注
-永续合约成交比例限频发布时间后续将会公布,敬请期待。
-原有永续合约滥用限频规则依然存在,即:
-成交率 = USDT成交金额 / (下单&撤单&修改订单请求数之和)
-24小时内请求次数超过86,400次请求,并且24小时内无任何订单成交,在下一小时内,永续合约下单限频被限制10r/10s;
-24小时内请求次数超过86,400次请求,并且成交阈值低于1%,在下一小时内,永续合约下单限频为被限制20r/10s。
-现货的成交比例限频,敬请期待。
-#返回格式
-所有的接口返回都是 JSON 格式,需要用户自行转换提取数据。 所有操作成功时都会返回 HTTP 状态码 2xx 。401 说明认证有问题。其他 4xx 状态码说明请求无效。 如果是 5xx 错误,则是服务端处理请求时遇上了未知的严重错误,碰到的话请第一时间反馈。
-
-返回状态
-
-返回格式
-状态码 说明
-200/201 请求执行成功
-202 请求已被服务端接受,但是仍在处理中
-204 请求成功,服务端没有提供返回体
-400 无效请求
-401 认证失败
-404 未找到
-429 请求过于频繁
-5xx 服务器错误
-#数据类型
-数据类型
-类型 说明
-string 字符串类型,以双引号表示,涉及金额和价格也会使用字符串标识
-integer 32位整数,主要涉及到状态码、大小、次数等
-integer(int64) 64位整数,主要涉及到ID和高精度时间戳
-number 浮点数,部分时间或统计数据会以浮点形式返回
-object 对象,包含一个子对象{}
-array 数组,包含多组内容
-boolean true 为真,false 为假
-#统一帐户(旧)
-统一账户旧版已不再维护,新版统一账户请查询统一账户
-
-我们从 4.25.0 版本之后开始引入对统一账户的支持 。统一账户是Gate新⼀代的交易系统,主要功能在于打破经典账户 (Classic Account) 内各个账户之间的资金隔离,实现多产品业务线之间的多币种保证金共享,用户无需各类交易之间进行资金划转,不同交易产品之间仓位盈亏可以互相抵消,有效提升用户的资金利用率。统一帐户(旧)更详细介绍可以查看 帮助中心 。
-
-用户在使用统一账户(旧) API 功能之前需要先在官网 API 管理页面创建统一账号(旧)的 API Key , 目前统一账户(旧)只支持现货全仓杠杆和永续合约交易。
-
-如果创建 API Key 的权限选项无法选择,首先确保现货全仓账户已经开通并且有初始资金。
-
-#资金划转
-经典帐户与统一帐户是两个不同的帐户,如果想实现多产品业务线之间的多币种保证金共享则必须使用统一帐户。
-
-统一账户(旧)的资金来源于经典账户,由于涉及到经典账户的资金变动,资金的转入转出操作都只能使用经典账户的 API Key 来执行。
-
-统一账户(旧)基于原有经典账户的全仓杠杆账户升级,因此经典账户只需要将自己的现货资金划转到现货全仓杠杆账户,即可为统一账户(旧)充值。 同理资金的转出操作也必须由经典账户从全仓杠杆账户划转到自己的现货账户。
-
-统一账户(旧)的 API Key 只能在自己的多个账户之间划转, 由于保证金共享,统一账户(旧)也无需将全仓账户的资金划转到合约账户 (我们也限制了向合约账户的转入功能)。 但是如果合约账户有资金需要提取,必须由统一账户(旧)划转到自己的现货全仓杠杆账户,才可以交给经典账户执行资金转出动作。
-
-#现货交易
-统一账户(旧)的现货交易与经典账户几乎完全一致,除了在订单操作中需要指定 account 的地方必须要指定 cross_margin , 比如想挂 BTC_USDT 交易对的买单,下单请求会类似于
-
-POST /spot/orders
-
-{
- "currency_pair": "BTC_USDT",
- "account": "cross_margin",
- "side": "buy",
- ...
-}
-其他订单相关限制请直接参考各接口说明。
-
-需要特别说明的是,统一账户(旧)升级自经典账户的现货全仓杠杆账户,经典账户的 API Key 原先就支持操作现货全仓杠杆账户, 为了不影响经典账户已有的操作,我们依然保留了经典账户的这个功能。所以不管是经典账户还是统一账户(旧)的 API Key 都可以操作同一个现货全仓杠杆账户(注意合约账户是分开的)
-
-#永续合约交易
-统一账户(旧)永续合约的 API 操作与经典账户完全相同,不过当前只支持 USD 结算
-
-需要留意一下在合约交易的部份,并没有像现货交易在使用经典帐户 API Key 的时候有做对全仓杠杆帐户的兼容性处理,所以当使用经典帐户 API Key 进行合约交易的时候,资产是保留在 经典帐户-合约 下面,而使用统一帐户 API Key 进行合约交易的时候,资产是保留在 统一帐户-合约 下面,这两个是不同的合约帐号。另外在 经典帐户-现货 下的资金, 是无法与 经典帐户-合约 共享保证金的。
-
-#Trace ID
-API响应会携带header: X-Gate-Trace-ID 。这个header用于链路追踪。
-
-#Self-Trade Prevention(STP)
-#名词解释
-Self-Trade Prevention: 自成交保护机制,后文中都简称为STP
-
-CN: Cancel new,取消新订单,保留老订单
-
-CO: Cancel old,取消⽼订单,保留新订单
-
-CB: Cancel both,新旧订单都取消
-
-#成交策略
-目前支持三种自成交保护策略,分别是CN、CO、CB。
-
-我们实现了STP用户组来提供给用户,被添加到同一个组内的多个用户账户ID,自成交或彼此成交会受到限制,限制策略取决于用户账户以taker 角色下单时指定的stp_act参数。
-
-当用户的账户ID添加到指定STP用户组后,下单时可以自定义stp_act参数,系统会按照用户传入的策略进行STP用户组 内撮合成交的限制;如果下单时没有指定stp_act策略,成交时默认按照CN策略执行。
-
-当下单用户的账户ID没有进入任何STP用户组,同时下单又指定了stp_act参数,此时系统会报错,无法下单。用户需要去掉stp_act 参数,此时用户成交不受任何自成交策略限制。
-
-#接口参数调整
-以合约下单为例,有如下调整:
-
-POST /futures/{settle}/orders
-新增请求参数
-
-接口参数调整
-名称 位置 类型 必选 描述
-stp_act body string 否 stp策略,包括:
-- cn 取消新订单,保留旧订单
-- co 取消老订单,保留新订单
-- cb 取消老订单和新订单
-新增返回参数(查询订单列表接口同理)
-
-接口参数调整
-名称 类型 必选 限制 描述
-stp_act string 否 none STP策略,包括:
-- cn 取消新订单,保留旧订单
-- co 取消老订单,保留新订单
-- cb 取消老订单和新订单
-stp_id integer(int64) 否 只读 用户所在STP用户组的id,是引擎判断用户之间订单是否可以成交的依据。如果账户没有进入STP用户组,stp_id不返回。
-finish_as string 否 只读 结束方式:
-- stp: 订单发生自成交限制而被撤销
-#使用场景
-组织A下有多个账户,其中几个账户id分别为101,102,103。
-
-为了防止组织内部账户下单发生自成交,管理员创建了一个STP用户组,用户组id为100,将账户101和102加入到该STP用户组 中,此时组内成员为[101,102]
-
-T1: STP策略版本上线。
-
-T2: 组织A账户101下做空单后,市场订单深度没有与之匹配的订单可以撮合成交,此时下单角色是maker,订单状态是open 。返回参数会增加如下信息返回
-
-{
- "status":"open",
- "stp_act":"cn",
- "stp_id":100
-}
-T3: 组织A账户101/102下做多单后,市场深度匹配到101账户下的做空订单可以撮合成交,当前角色是taker ,系统判断到两个订单的stp_id均为100,此时会限制成交,限制策略以taker为准。
-
-如果选择了cn,taker下的订单会被取消,订单会结束,返回关键参数为:
-{
- "status":"finished",
- "stp_act":"cn",
- "stp_id":100,
- "finish_as":"stp"
-}
-如果选择了co,taker下的订单会被保留,订单状态为open,系统默认会取消maker的订单(maker可以通过查询订单列表,订单状态会跟上一种情况一致。)
-
-如果选择了cb,taker下的订单会被取消,订单会结束。系统默认会取消maker的订单(maker 可以通过查询订单列表)。两者的订单结束原因都为stp
-
-{
- "status":"finished",
- "stp_act":"cb",
- "stp_id":100,
- "finish_as":"stp"
-}
-T3': 组织A账户103下做多单后,市场深度匹配到101账户下的做空订单可以撮合成交,由于103用户没有被添加到组里,stp_id 为0,系统判断两边的stp_id不一致,可以成交。订单信息为:
-
-{
- "status":"finished",
- "stp_id":0,
- "finish_as":"filled"
-}
-#统一账户
-#说明
-用户开通统一账户后,可以使用现货账户中的资产作为交易的保证金, 账户内的各币种资产将会根据其流动性,定义相应的调整系数,再统一折算为USD,来统一计算账户的资产及持仓价值。
-
-统一账户最大可借贷额度是用户对于当前交易市场的最大借贷额度。平台将根据用户的可用保证金数量以及平台风控规则等限制,计算用户当前的最大借贷额度。统一账户产生自动借款后,平台即时对所借数字资产开始计息。
-
-目前统一账户支持开通多币种保证金模式,后续将推出组合保证金模式,可根据自身需求进行账户模式切换,敬请期待。
-
-相关的接口请查看统一账户文挡,开通统一账户后可进行调用。更详细介绍可以查看 帮助中心 。
-
-#API接入流程
-创建新 API KEY 或者更新已有 API KEY 权限,勾选 unified 权限
-使用经典账户 API KEY 调用 PUT /unified/unified_mode 接口,或者 WEB 页面升级新版统一账户
-使用 /api/v4/spot/** 接口进行现货相关操作(下单、修改订单、查询订单等), account 类型增加 unified 选项
-使用 /api/v4/futures/** 接口进行永续合约相关操作(下单、修改订单、查询订单等)
-使用 /api/v4/unified/** 接口进行统一账户相关操作(账户查询、借贷查询)
-#现货交易
-统一账户的现货交易与经典账户一致,在订单操作中指定 account=unified,或者指定account=spot系统检测账户为统一账户时会自动处理为统一账户订单, 比如想挂 BTC_USDT 交易对的买单,下单请求会类似于
-
-POST /spot/orders
-
-{
- "currency_pair": "BTC_USDT",
- "account": "unified",
- "side": "buy",
- ...
-}
-其他订单相关限制请直接参考各接口说明。
-
-#永续合约交易
-统一账户永续合约的 API 操作与经典账户完全相同,当前只支持 USDT 结算
-
-#保证金公式
-保证金公式详情见: 保证金公式
-
-#资产流水类型
-#通用
-unknown : 未知
-login : 登陆
-withdraw : 提现
-ch_pass : 修改密码
-ch_fund_pass : 修改资金密码
-login_failed : 登录失败
-axs_account : 访问账号
-req_pass_ch : 修改密码请求
-req_fund_pass_ch : 修改资金密码请求
-fund_pass_ent : 输入交易密码
-bank_card_add : 绑定银行卡
-frw : 提现人脸验证
-#订单
-new_order : 下单
-cancel_order : 取消订单
-order_fill : 成交
-order_rej : 订单退回
-order_fee : 成交手续费
-system_fee : 系统成交手续费
-#充提
-withdraw : 提现
-deposit : 充值
-deposit_rej : 充值退回
-withdraw_rej : 提现退回
-cancel_withdraw : 取消提现
-withdraw_gatecode : 充值码提现
-withdraw_fireblock : Fireblock提现
-withdraw_copper : Copper提现
-startup_withdraw : Startup项目提现
-deposit_gatecode : 充值码充值
-deposit_fireblock : Fireblock充值
-deposit_copper : Copper充值
-buy_cl : 法币入金 Legend
-buy_cc : 法币入金 Cabital
-deposit_finmo : Finmo充值
-#Startup
-startup_prtcp : 参加Startup
-startup_refund : 退回Startup
-startup_sale : Startup认购
-startup_sale_rb : Startup认购退回
-#返佣
-referral_rebate : 推荐奖励
-sec_rebate_out : 二级返佣系统账户转出
-sec_rebate_in : 用户获得二级返佣
-ab_rebate : API Broker返佣上级收入
-eb_rebate : Exchange Broker返佣上级收入
-u_rebate : 普通邀请返佣用户收入
-ads_rebate : 代理商直接上级返佣收入
-au_rebate : 代理商返佣用户收入
-pis_rebate : 合伙人间接上级返佣收入
-pds_rebate : 合伙人直接上级返佣收入
-pu_rebate : 合伙人用户返佣收入
-#兑换
-eth_swap : ETH分叉兑换
-dust_swap_dctd : 小额资产兑换
-dust_swap_gt_add : 小额资产GT增加
-dust_swap_fee : 小额币种手续费扣除
-cv_buy : 闪兑买入
-cv_sell : 闪兑卖出
-#C2C
-c2c_mop : C2C商家下单
-c2c_moc : C2C取消商家单
-c2c_rop : C2C用户下单
-c2c_roc : C2C取消用户单
-c2c_om : C2C成交
-c2c_or : C2C退回
-c2c_fee : C2C手续费
-#奖励
-deposit_bonus : 充值奖励
-trading_rewards : 交易奖励
-purchase_bonus : 买入奖励
-airdrop : 空投奖励
-award : 限时奖励
-mining_rewards : 挖矿奖励
-#账户出入金
-margin_in : 逐仓杠杆转入
-margin_out : 逐仓杠杆转出
-spot_settle_out: 现货同币种结算转出
-spot_settle_in: 现货同币种结算转入
-lending_in : 理财转入
-lending_out : 理财转出
-cross_in : 统一账户转入
-cross_out : 统一账户转出
-perp_in : 永续合约转入
-perp_out : 永续合约转出
-perp_settle_in: 永续合约多币种结算转入
-perp_settle_out: 永续合约多币种结算转出
-delivery_in : 交割合约转入
-delivery_out : 交割合约转出
-ai_in : 定投转入
-ai_out : 定投转出
-e_options_in : 短时期权转入
-e_options_out : 短时期权转出
-options_in : 期权转入
-options_out : 期权转出
-cbbc_in : 牛熊证转入
-cbbc_out : 牛熊证转出
-warrant_in : 窝轮转入
-warrant_out : 窝轮转出
-subaccount_trf : 子账户资金划转
-quant_in : 量化交易转入
-quant_out : 量化交易转出
-pay_in : 支付账户转入
-pay_out : 支付账户转出
-fct_in : 合约跟单交易转入
-fct_out : 合约跟单交易转出
-#点卡
-points_purchase : 购买点卡
-points_expiration : 限时点卡
-points_trf : 点卡转让
-points_trf_rej : 点卡转让退回
-#金融
-lending_lent : 理财借出
-collected : 收款
-interest_in : 利息收入
-lending_fee : 理财手续费抵扣
-hodl_int : PoS利息收益
-redeem : 赎回
-lend : 借出
-dual_purchased : 双币理财申购
-dual_settled : 双币理财结算
-liq_add : 流动性添加
-liq_rm : 流动性赎回
-liq_rebalanced : 流动性调仓
-slot_int_in : 插槽解锁利息收益
-str_int_in : 结构性理财利息收益
-#借贷
-borrow : 借款
-repay : 还款
-margin_borrow : 逐仓杠杆借入
-margin_repay : 逐仓杠杆还款
-margin_interest_out : 逐仓杠杆扣息
-cl_borrow : 抵押借入
-cl_repay : 抵押还款
-cl_dctd : 抵押扣除
-cl_rtd : 抵押退还
-cross_borrow : 统一账户借入
-cross_repay : 统一账户还款
-interest_out : 利息
-#币圈
-donation : 捐款
-rp_sent : 发送红包
-rp_rcvd : 收取红包
-rp_rej : 红包退回
-ls_offered : 直播打赏
-ls_rcvd : 直播被打赏
-pt_offered : 币圈打赏
-pt_rcvd : 币圈被打赏
-subs_deduct : 订阅扣费
-subs_in : 订阅费入账
-subs_refund : 订阅费退回
-subs_in_rcvd : 订阅费用退回入账
-#PUSH交易
-push_dctd : push扣除
-push_rcvd_dctd : push接收扣除
-push_canceled : push撤单
-push_rej : push拒绝
-push_sent : push转让
-push_rcvd : push接收
-#量化跟单
-quant_return : 量化交易退回
-quant_cmn_in : 量化复制分红转入
-quant_cmn_out : 量化复制分红转出
-quant_cmn_rtd : 量化复制分红退回
-fct_refund : 合约跟单交易资金退回
-fct_rcvd : 合约带单分红转入
-fct_fee : 合约跟单分红转出
-fct_fee_refund : 合约跟单分红资金退回
-#NFT
-nft_mp : 拍卖支付保证金
-nft_bm : 拍卖购买
-nft_om : 拍卖出售
-ntf_mr : 拍卖保证金退回
-nft_amr : 拍卖流拍获得保证金
-nft_ocb : 订单取消退回
-nft_fb : 一口价购买
-nft_fs : 一口价出售
-nft_ob : 报价购买
-nft_os : 报价出售
-nft_cr : 取消报价退款
-nft_ir : 报价失效退款
-nft_wf : 提现服务费
-nft_wfr : 提现手续费退回
-ntf_mf : 多副本创作服务费
-ntf_mfr : 多副本创作服务费退回
-ntf_royalty : 用户版税收入
-nft_cd : 订单取消扣款
-nft_crd : 交易撤销版税扣款
-nft_cf : 众筹差额扣款
-nft_cfr : 众筹差额退款
-nft_ammf : 流动性池充值冻结
-nft_ammw : 流动性池提现
-nft_ammdf : 流动性池手续费
-nft_ammd : 流动性池交易成功打款
-#资产流水编码
-#资产
-#C2C
-301 : C2C商家下单
-302 : C2C 取消商家单
-303 : C2C用户卖出
-304 : C2C取消用户单
-305 : C2C用户买入
-308 : C2C手续费
-309 : C2C 保证金冻结
-310 : C2C 保证金退回
-311 : C2C 保证金赔付
-312 : C2C共享资产退回
-313 : C2C申诉冻结
-314 : C2C 申诉解冻
-315 : C2C 快捷闪兑买入
-110106 : C2C 商家保证金理财利息
-#充值
-110 : 链上充值
-121 : 充值码
-122 : Fireblocks充值
-123 : Wrongdeposit Fee
-124 : Copper 充值
-125 : 资产寻回手续费退回
-1907 : push转让
-1908 : 手机/邮箱/UID 充值
-2650 : Bitgo 充值
-5107 :
-#兑换
-1301 : 小额资产兑换
-1302 : 小额资产GT增加
-1307 : 小额资产兑换
-1310 : 小额资产兑换
-1322 : 小额资产兑换(USDT)
-1323 : 小额兑换USDT增加
-2601 : 闪兑买入
-2602 : 闪兑卖出
-2603 : 一键还款出账
-2604 : 一键还款入账
-2605 : 闪兑买入
-2606 : 闪兑卖出
-2612 : 闪兑买入
-2613 : 闪兑卖出
-2615 : OTC-订单成交
-2616 : OTC-订单成交
-#其他
-106 : 捐款
-115 : 快照
-118 : 币种基数调整
-131 : 集合竞价冻结
-132 : 集合竞价解冻
-141 : ETF资产合并-扣款
-142 : ETF资产合并-加款
-143 : 币种更名扣款
-144 : 币种更名加款
-181 : ETH分叉兑换
-182 : ETH2兑换
-329 : Gate Connect-退款
-330 : Gate Connect-购买
-331 : Gate Connect-卖出
-501 : 领取分叉币
-502 : 返还分叉币
-801 : 发送红包
-802 : 收取红包
-803 : 红包退回
-804 : 直播打赏
-805 : 直播被打赏
-806 : 币圈打赏
-807 : 币圈被打赏
-903 : 限时点卡
-913 : 点卡兑换商品
-915 : 点卡兑换商品退回
-917 : 点卡过期回收
-1001 : 法币借贷发布广告单
-1002 : 法币借贷撤销广告单
-1003 : 法币借贷下单
-1004 : 法币借贷完成还款
-1005 : 法币借贷撤单
-1006 : 法币借贷手续费
-1007 : 法币借贷平仓
-1008 : 法币借贷补仓
-1311 : 小额资产兑换
-1312 : 小额资产USDT增加
-1501 : 订阅扣费
-1502 : 订阅费入账
-1503 : 订阅费退回
-1504 : 订阅费用退回入账
-2950 : BUGSFUNDED 报名费
-2951 : BUGSFUNDED 报名费退款
-2952 : BUGSFUNDED 实盘资金-扣款
-2953 : BUGSFUNDED 利润划出
-2954 : BUGSFUNDED 利润划入
-2956 : BUGSFUNDED 实盘资金-划入
-2970 : PUMP售卖活动-退回购买金额
-2971 : PUMP售卖活动-发放代币
-2972 : PUMP售卖活动-扣除购买金额
-3701 : OTC交易-买入
-3702 : OTC交易-卖出
-3703 : OTC交易-取消
-5104 : Fireblocks手续费退回
-5105 : 预扣 Gas 费
-5106 : 回滚预扣 Gas 费
-100101 : 平仓尾差转出
-100102 : 平仓尾差转入
-110101 : 低流通币种提现手续费退回
-110102 : 低流通币种提现手续费
-130101 : 创建代币
-130102 : 创建代币失败退回
-130111 : KOL 代币未上市退款
-130112 : KOL 代币超额认购退款
-130113 : KOL 代币赎回
-130114 : KOL 代币认购
-130115 : KOL 代币链上手续费
-130118 : KOL 代币链上手续费退款
-130119 : KOL 代币认购失败退款
-150101 : 币种回购-加款
-150102 : 货币回购-借记
-150201 : 借入映射资金
-150202 : 归还映射资金
-150203 : 转入资金
-150204 : 转出资金
-150208 :
-180101 : Alpha 代币下架退款
-#划转
-601 : 转出至杠杆账户
-602 : 从杠杆账户转入
-701 : 转出至永续合约账户
-702 : 从永续合约账户转入
-703 : 转出至交割合约账户
-704 : 从交割合约账户转入
-1401 : 子账号资金划转
-150215 : 子账号资金划转
-150216 : 子账号资金划转
-150217 : 子账号资金划转
-150218 : 子账号资金划转
-150219 : 子账号资金划转
-1603 : 转出至期权账户
-1604 : 从期权账户转入
-3001 : 转出至支付账户
-3008 : 从支付账户转入
-3028 : 支付账户划转(退款)
-100202 : 转出至 TradFi 账户
-170201 : 从跨所账户转入
-170204 : 转出至跨所账户
-#奖励
-120102 : 合约积分空投
-#提现
-4 : 链上提现
-17 : 充值码提现
-18 : Fireblocks提现
-19 : Copper 提现
-104 : 取消链上提现
-1901 : 手机/邮箱/UID 提现
-1903 : push接收扣除
-1905 : 手机/邮箱/UID 取消提现
-1906 : 手机/邮箱/UID 提现退回
-2651 : Bitgo 提现
-#支付
-2609 : 闪兑买入
-2610 : 闪兑卖出
-2611 : 闪兑退款
-3001 : 转出至支付账户
-3017 :
-3018 : 划转(下发)
-3019 : 提现法币
-3020 : 提现法币退款
-3024 :
-3026 : 收款
-3027 : 退款
-3519 : 礼品卡 - 创建
-3520 : 礼品卡 - 兑换
-190101 : 结算 - 增加
-190301 : 待接收
-190305 : 转账成功
-190306 : 超时退回
-190307 : 已撤销
-#活动&奖励
-401 : 充值奖励
-402 : 交易奖励
-403 : 买入奖励
-404 : 空投奖励
-405 : 反馈奖励
-3101 : 卡券中心点卡兑换
-3104 : 现货代币空投
-3105 : 卡券手续费返现
-3120 : Candydrop 奖励
-3150 : 活动代币发放失败
-3801 : 体验券盈利结转
-120101 : 合约积分奖励
-140203 : 现金券奖励兑换
-140204 : 激励空投
-140205 : 激励空投解锁
-140206 : 激励空投回收
-140207 : 锁仓扣除
-#现货大宗交易
-3401 : 现货大宗交易转入
-3402 : 现货大宗交易转出
-#返佣
-109 : 普通邀请上级推荐返佣
-162 : 代理商间接上级返佣收入
-164 : 代理商直接上级返佣收入
-166 : 代理商返佣用户收入
-191 : 普通邀请返佣用户收入
-3301 : 超级代理商直接上级返佣
-3321 : Affiliate Ultra Indirect Superior Rebate
-3341 : 超级代理商自返佣
-3381 : 观察期返佣
-3390 : API Broker返佣上级收入
-3410 : Exchange Broker返佣上级收入
-4002 : 佣金提取收入
-4009 : 用户奖励自提
-4011 : 扣除负maker
-#交易
-#期权
-dnw : 转入转出
-fee : 交易手续费
-prem : 权利金
-refr : 推荐人返佣
-set : 结算盈利
-#永续
-bonus_dnw : 体验金充提
-bonus_offset : 体验金抵扣
-dnw : 转入转出
-fee : 交易手续费
-fund : 资金费用
-pnl : 减仓盈亏
-point_convert : 点卡转化
-point_dnw : 点卡转入转出
-point_fee : 点卡交易手续费
-point_refr : 点卡推荐人返佣
-pv_dnw : 体验仓位赠金充值与回收
-refr : 推荐人返佣
-#交割
-dnw : 转入转出
-fee : 交易手续费
-pnl : 减仓盈亏
-point_dnw : 点卡转入转出
-point_fee : 点卡交易手续费
-point_refr : 点卡推荐人返佣
-refr : 推荐人返佣
-settle : 结算
-settle_fee : 结算手续费
-#Alpha
-6001 : Alpha 下单
-6002 : Alpha 下单
-6003 : Alpha 成交
-6004 : Alpha 成交
-6005 : Alpha 交易失败
-6006 : Alpha 交易失败
-6007 : MemeBox 交易手续费
-6010 : Alpha 空投
-6011 : Alpha 买入订单撤销
-6012 : Alpha 买入订单撤销
-130103 : Alpha 闪兑卖出
-130104 : Alpha 闪兑买入
-130105 : Alpha 闪兑失败退回
-130106 : Alpha 闪兑卖出
-130107 : Alpha 闪兑买入
-130108 : Alpha 闪兑失败退回
-#交易机器人
-1701 : 机器人交易转入
-1702 : 机器人交易转出
-1703 : 机器人交易退回
-2401 : 机器人复制分红转入
-2402 : 机器人复制分红转出
-2403 : 机器人复制分红退回
-150210 : 期权机器人交易转入
-150211 : 期权机器人交易转出
-#保证金交易
-659 : 异币种还款入账
-660 : 异币种还款出账
-670 : 保证金交易借入
-671 : 保证金交易还款
-672 : 保证金交易扣息
-682 : 补充保险基金
-683 : 保险基金填补损失
-685 : 平台借币扣息
-#现货
-101 : 卖出
-102 : 买入
-151 : 成交手续费
-#跟单
-3151 : 跟单无忧金赔付
-3201 : 合约跟单交易转入
-3202 : 合约跟单交易转出
-3203 : 合约跟单交易资金退回
-3204 : 合约带单分红转入
-3205 : 合约跟单分红转出
-3206 : 合约跟单分红资金退回
-3601 : 现货带单交易转入
-3602 : 现货带单交易转出
-3603 : 现货带单交易退回
-3604 : 现货跟单交易转入
-3605 : 现货跟单交易转出
-3606 : 现货跟单交易资金退回
-3607 : 现货带单分红转入
-3608 : 现货跟单分红转出
-3609 : 现货跟单分红资金退回
-210101 : 跟单体验金回收
-210102 : 跟单体验金发放
-#逐仓杠杆
-601 : 转出至杠杆账户
-602 : 从杠杆账户转入
-605 : 逐仓杠杆借入
-606 : 逐仓杠杆还款
-616 : 强平手续费
-675 : 逐仓杠杆计息
-676 : 逐仓杠杆扣息
-#理财
-#HODLer Airdrop
-2614 : HODLer Airdrop
-#Launchpad
-1134 : Launchpad 扣款
-1135 : Launchpad 退回
-1136 : Launchpad 分发
-1203 : Launchpad 锁仓
-#Launchpool
-1174 : 邀请奖励
-1251 : 质押
-1253 : 主动赎回
-1255 : 派息奖励
-1258 : 自动赎回
-#余币宝
-661 : 赎回-活期
-662 : 申购-活期
-669 : 利息收益-活期
-681 : 额外奖励-活期
-686 : 申购-定期
-687 : 赎回-定期
-688 : 利息收益-定期
-689 : 额外奖励-定期
-160301 : 定期理财利息收益
-160302 : 定期理财额外奖励
-160303 : 定期理财赎回
-160304 : 定期理财申购
-160401 : 加息收益-定期
-160402 : 定期理财加息收益
-160406 : Boost 奖励-定期
-#双币宝
-2001 : 双币投资申购
-2004 : 双币投资结算
-2011 : 申购抄底宝产品
-2012 : 抄底宝产品到期回款
-2021 : 申购逃顶宝产品
-2022 : 逃顶宝产品到期回款
-160201 : 双币投资到期回款
-160202 : 双币投资申购
-#定投理财
-911 : 定投转出
-912 : 定投转入
-#抵押借币
-635 : 固定利率抵押利息
-640 : 活期扺押借入
-641 : 活期抵押还款
-642 : 活期平仓还款
-643 : 活期平仓利息
-644 : 活期抵押利息
-645 : 抵押扣除
-646 : 抵押退还
-647 : 抵押调整
-648 : 平仓退还
-649 : 平仓手续费
-655 : 固定利率抵押借入
-656 : 固定利率抵押还款
-657 : 固定利率平仓还款
-658 : 固定利率平仓利息
-696 : 提前还款违约金
-697 : 提前还款违约金退还
-160601 : 平仓赎回余币宝保证金扣款
-160602 : 平仓剩余余币宝保证金退还
-#持币生息
-120103 : 合约持币生息
-160501 : 现货持币生息
-#杠杆无忧
-160608 : 杠杆无忧到期回款
-160609 : 杠杆无忧申购
-#私募基金
-160101 : 私募基金到期回款
-160102 : 私募基金申购
-160103 : 私募基金手动赎回回款
-160104 : 私募基金收益
-#第三方基金
-170101 : 第三方基金申购款
-170111 : 第三方基金赎回款
-170112 : 第三方基金清算款
-170113 : 第三方基金申购失败退款
-170206 : 第三方基金现金分红款
-#量化基金
-739 : 财富管理返佣
-751 : 量化基金锁仓
-753 : 量化基金解锁
-754 : 量化基金解锁收益
-#链上赚币
-1171 : 额外奖励
-1173 : 额外奖励
-1181 : 质押
-1184 : 赎回
-1186 : 利息派发
-1191 : 质押
-1194 : 赎回
-1196 : 利息派发
-160607 : 撤销赎回
-#异常处理
-APIv4 对于所有的异常请求,会设置状态码为非 2xx ,同时返回一个 JSON 格式的返回体来描述具体的错误信息。
-
-返回体的格式通常如下所示:
-
-{
- "label": "INVALID_PARAM_VALUE",
- "message": "Invalid parameter `text` with value: abc"
-}
-label 用于标识某种错误的类型,格式 string ,它的值是一个固定的列表(见下方)。程序处理可以使用 label 字段的内容来设定和捕获异常
-message (或 detail) 表示详细的错误信息,方便 API 对接时,理解具体是因为什么样的参数设置导致请求出现了异常。 该字段内容不建议用于异常的捕获或识别。
-以 Python requests (opens new window)为例,异常的处理流程可以参考如下所示:
-
-以下示例的异常捕获流程只涉及到业务相关的异常,网络连接超时等其他非业务相关的异常还需要自行处理。
-
-import requests
-
-r = requests.get("https://api.gateio.ws/api/v4/futures/btc/contracts/BTC_USD")
-try:
- r.raise_for_status()
-except requests.HTTPError:
- # 捕获非 2xx 错误,尝试解析 body 里返回的错误消息,并根据不同 label 做不同的异常处理
- if r.json()['label'] == 'xxx':
- print(r.json())
-以 Python SDK (opens new window)为示例:
-
-import json
-from gate_api import FuturesApi
-from gate_api.rest import ApiException
-
-api = FuturesApi()
-try:
- api.get_futures_contract(settle='btc', contract="BTC_USD")
-except ApiException as e: # ApiException 封装了异常的各种信息,详情可参看类定义
- detail = json.loads(e.value.body)
- if detail['label'] == 'xxx':
- print(detail)
-#异常 label 列表
-请求参数或格式问题
-异常 label 列表
-label 含义
-INVALID_PARAM_VALUE 参数输入值无效
-INVALID_PROTOCOL 参数输入值无效
-INVALID_ARGUMENT 参数无效
-INVALID_REQUEST_BODY 无效请求体
-MISSING_REQUIRED_PARAM 缺少必选参数
-BAD_REQUEST 无效请求
-INVALID_CONTENT_TYPE 无效的 Content-Type 头部格式
-NOT_ACCEPTABLE Accept 头部无法满足
-METHOD_NOT_ALLOWED 请求方法不接受
-NOT_FOUND 资源 URL 不存在
-认证相关
-异常 label 列表
-label 含义
-INVALID_CREDENTIALS 认证接口缺少用户认证信息
-INVALID_KEY 无效的 API Key
-IP_FORBIDDEN 请求 IP 不在白名单
-READ_ONLY 请求账户只读,不可执行写操作
-INVALID_SIGNATURE 无效签名
-MISSING_REQUIRED_HEADER 缺少必要的认证头部
-REQUEST_EXPIRED 客户端时间与服务端时间相差过大
-ACCOUNT_LOCKED 账户被锁定
-FORBIDDEN 账户无权执行该操作
-API_WITHDRAW_DISABLED API提现操作临时禁用
-INVALID_WITHDRAW_ID 无效的提现ID
-INVALID_WITHDRAW_CANCEL_STATUS 当前提现状态无法取消
-钱包相关
-异常 label 列表
-label 含义
-SUB_ACCOUNT_NOT_FOUND 子账户不存在
-SUB_ACCOUNT_LOCKED 子账号被冻结
-MARGIN_BALANCE_EXCEPTION 杠杆账户异常
-MARGIN_TRANSFER_FAILED 杠杆资金划转失败
-TOO_MUCH_FUTURES_AVAILABLE 合约账户总资产达到上限
-FUTURES_BALANCE_NOT_ENOUGH 合约账户余额不足
-ACCOUNT_EXCEPTION 账户异常
-SUB_ACCOUNT_TRANSFER_FAILED 子账户资金划转失败
-ADDRESS_NOT_USED 指定的钱包地址未在网页执行过划转
-TOO_FAST 提现频率过快
-WITHDRAWAL_OVER_LIMIT 超出提现额度
-DUPLICATE_REQUEST 重复请求
-ORDER_EXISTS 订单已存在
-INVALID_CLIENT_ORDER_ID 无效的client_order_id
-RISK_ERROR 触发风控
-NEGATIVE_ASSETS 安全提现检查存在负资产
-RECEIVE_ERROR 接收失败
-DEDUCTION_ERROR 转账人扣款失败
-FINANCE_ERROR 财务账户扣款失败
-BALANCE_NOT_ENOUGH 余额不足
-现货和杠杆相关
-异常 label 列表
-label 含义
-INVALID_PRECISION 无效的精度
-INVALID_CURRENCY 无效的币种信息
-INVALID_CURRENCY_PAIR 无效的交易对
-POC_FILL_IMMEDIATELY 被动委托会立即成交
-ORDER_NOT_FOUND 订单不存在
-ORDER_CLOSED 订单已结束
-ORDER_CANCELLED 订单已撤销
-QUANTITY_NOT_ENOUGH 数量不足
-BALANCE_NOT_ENOUGH 余额不足
-MARGIN_NOT_SUPPORTED 该交易对不支持杠杆交易
-MARGIN_BALANCE_NOT_ENOUGH 杠杆账户余额不足
-AMOUNT_TOO_LITTLE 数额小于最低值
-AMOUNT_TOO_MUCH 数额过大
-REPEATED_CREATION 重复创建
-LOAN_NOT_FOUND 借贷订单不存在
-LOAN_RECORD_NOT_FOUND 借贷记录不存在
-NO_MATCHED_LOAN 没有借贷记录能满足借入需求
-NOT_MERGEABLE 借贷单不可合并
-NO_CHANGE 修改的参数与当前状态无区别
-REPAY_TOO_MUCH 还款数额超出借款数额
-TOO_MANY_CURRENCY_PAIRS 批量下单指定了过多交易对
-TOO_MANY_ORDERS 批量下单的单个交易对下单数过多
-MIXED_ACCOUNT_TYPE 批量下单中使用了多个账户类型
-AUTO_BORROW_TOO_MUCH 自动借入超出最多可借
-TRADE_RESTRICTED 高负债率导致交易操作被限制
-FOK_NOT_FILL FOK 订单无法全部成交
-INITIAL_MARGIN_TOO_LOW 用户总初始保证金率太低
-NO_MERGEABLE_ORDERS 找不到能够合并的借贷订单
-ORDER_BOOK_NOT_FOUND 市场深度不足
-FAILED_RETRIEVE_ASSETS 获取账户资产失败
-CANCEL_FAIL 订单撤销失败
-PRICE_THRESHOLD_EXCEEDED 触发限价保护
-合约相关
-异常 label 列表
-label 含义
-USER_NOT_FOUND 用户无合约账户
-CONTRACT_NO_COUNTER 没有匹配的对手单
-CONTRACT_NOT_FOUND 合约未找到
-NOT_FOUND 请求路径不存在
-RISK_LIMIT_EXCEEDED 委托超出风险限额
-INSUFFICIENT_AVAILABLE 余额不足
-LIQUIDATE_IMMEDIATELY 操作可能导致爆仓
-LEVERAGE_TOO_HIGH 杠杆倍数设置过高
-LEVERAGE_TOO_LOW 杠杆倍数设置过低
-ORDER_NOT_FOUND 委托不存在
-ORDER_NOT_OWNED 委托不存在
-ORDER_FINISHED 委托已结束
-TOO_MANY_ORDERS 过多未完成的委托
-POSITION_CROSS_MARGIN 全仓不支持更新保证金
-POSITION_IN_LIQUIDATION 仓位在强制平仓中
-POSITION_IN_CLOSE 仓位正在平仓中
-POSITION_EMPTY 仓位为空
-REMOVE_TOO_MUCH 保证金超过可调范围
-RISK_LIMIT_NOT_MULTIPLE 风险限额未按照步长调整
-RISK_LIMIT_TOO_HIGH 超出最大风险限额
-RISK_LIMIT_TOO_lOW 风险限额设置过低
-PRICE_TOO_DEVIATED 下单价与标记价格相差过大
-SIZE_TOO_LARGE 下单数量超过上限
-SIZE_TOO_SMALL 下单数量不足下限
-PRICE_OVER_LIQUIDATION 增加仓位时价格不能超过平仓价
-PRICE_OVER_BANKRUPT 减少仓位时价格不能超过破产价
-ORDER_POC_IMMEDIATE 被动委托会立即成交
-INCREASE_POSITION 只减仓委托会增加仓位
-CONTRACT_IN_DELISTING 当前合约市场处于下线过渡期,只允许创建只减仓委托或者平仓委托
-POSITION_NOT_FOUND 仓位不存在
-POSITION_DUAL_MODE 双向持仓模式不允许此操作
-ORDER_PENDING 有委托存在则不允许此操作
-POSITION_HOLDING 有持仓则不允许此操作
-REDUCE_EXCEEDED 双向持仓模式下,减仓单超过仓位大小
-NO_CHANGE 没有改变发生
-AMEND_WITH_STOP 有止盈止损单时不能修改委托
-ORDER_FOK FOK 订单无法全部成交
-抵押借币相关
-异常 label 列表
-label 含义
-COL_NOT_ENOUGH 质押物余额不足
-COL_TOO_MUCH 超过质押币种质押额度
-INIT_LTV_TOO_HIGH 初始质押率过高
-REDEEMED_LTV_TOO_HIGH 提取后质押率过高
-BORROWABLE_NOT_ENOUGH 剩余可借余额不足
-ORDER_TOO_MANY_TOTAL 超过平台每天下单数量
-ORDER_TOO_MANY_DAILY 超过单一用户每天下单数量
-ORDER_TOO_MANY_USER 超过单一用户总下单数量
-ORDER_NOT_EXIST 订单不存在
-ORDER_FINISHED 订单已结束
-ORDER_NO_PAY 订单待还金额为0
-ORDER_EXIST 订单已存在
-ORDER_HISTORY_EXIST 订单历史记录已存在
-ORDER_REPAYING 订单已在还款中
-ORDER_LIQUIDATING 订单已在平仓中
-BORROW_TOO_LITTLE 小于币种最小可借
-BORROW_TOO_LARGE 借款金额超过最大剩余可借
-REPAY_AMOUNT_INVALID 还款金额无效
-REPAY_GREATER_THAN_AVAILABLE 还款数额大于剩余可用
-POOL_BALANCE_NOT_ENOUGH 资金池余额不足
-CURRENCY_SETTLING 币种结算中,不允许还款
-RISK_REJECT 风控检查中,请稍后再试
-LOAN_FAILED 放款失败,可以再次发起借款
-现货保证金相关
-异常 label 列表
-label 含义
-USER_LIAB 用户存在负债
-USER_PENDING_ORDERS 用户存在挂单
-MODE_SET 保证金模式已设置
-理财相关
-异常 label 列表
-label 含义
-ERR_BALANCE_NOT_ENOUGH 余额不足
-ERR_PRODUCT_SELL_OUT 项目售罄
-ERR_PRODUCT_BUY 项目未开始
-ERR_CREATE_ORDER 下单失败
-ERR_QUOTA_LOWER_LIMIT 不满足最小下单金额
-ERR_QUOTA_SUPERIOR_LIMIT 已达最大下单额度
-ERR_ORDER_NUMBER_LIMIT 已达最大下单数量
-ERR_PRODUCT_CLOSE 项目已结束
-COPIES_NOT_ENOUGH 可申购仓位不足
-COPIES_TOO_SMALL 投资份额不足
-COPIES_TOO_BIG 投资份额超过最大购买限制
-TOTAL_AMOUNT_24 24小时内质押与赎回总量超限
-TOTAL_BUYCOUNT_24 24小时内质押与赎回次数超限
-REDEEM_24_LIMIT 质押后24小时内不能赎回
-服务异常
-异常 label 列表
-label 含义
-INTERNAL 内部错误
-SERVER_ERROR 内部错误
-TOO_BUSY 服务当前忙
-闪兑相关
-异常 label 列表
-label 含义
-INVALID_PARAM_VALUE 参数不合法
-INVALID_CURRENCY 不支持的币种
-INVALID_CURRENCY_PAIR 无效交易对
-PRICE_OBSOLETE 价格已失效/过期/作废
-ORDER_NOT_FOUND 订单不存在
-ORDER_BOOK_NOT_FOUND 订单簿不存在
-BALANCE_NOT_ENOUGH 余额不足,划转失败
-TOO_MANY_REQUESTS 请求过于频繁
-QUOTA_NOT_ENOUGH 额度不足
-SERVER_TIMEOUT 服务超时
-MISSING_REQUIRED_PARAM 缺失必要参数
-REQUEST_FORBIDDEN 资管账户访问限制
-CONVERT_PREVIEW_EXPIRED 预览缓存过期
-CONVERT_PREVIEW_NOT_MATCH 预览数据不一致
-AMOUNT_TOO_LITTLE 金额太小
-AMOUNT_TOO_MUCH 金额太大
-#认证
-#生成 API key
-在调用私有API接口前,需要生成账户的API key来验证身份。 您可以在网页端登录成功后,在【账户管理】-> 【APIv4 Keys】中生成, 或点击 这里 生成 API keys
-
-每个账户最多可以创建 20 个 API key,每个 Key 的权限配置都是相互独立的。 建议给每个 Key 设置能够标明用途的备注名
-
-Key 访问密钥
-Secret Key 签名认证加密所使用的密钥
-
-除此之外,还可以配置 IP 白名单,只允许服务端接收来自 IP 白名单里的客户端请求。每个 Key 最多可配置 20 个 IP 地址,IP 地址按照 IPv4 配置, 不支持 IP 地址段。若不设置 IP 白名单,服务端不会验证客户端 IP 来源。
-
-注:如果发现 Key 的名字是 spot 或者 futures ,该 Key 很有可能是迁移之后系统的默认命名, 详情参考 “关于 APIv4 Key 升级” 一节。
-
-创建的 Key 还可以更新和删除,不过需要注意的是 Key 的更新和删除,最多需要 5 分钟才能生效。
-
-另外模拟合约与实盘合约属于两套不同的环境,实盘合约的 API Key 不可用于模拟合约。 如果需要使用模拟合约做 API 接口联调测试,需要在个人账户 APIv4Keys 页面的模拟合约入口单独申请。 模拟合约与实盘合约的接口请求方式完全相同,区别只是在 API 的 Base URL 和使用的 API Key
-
-#APIv4 权限
-创建 Key 的时候,可以为该 Key 配置是否开启现货杠杆、合约、钱包或者提现的权限, 开启的权限可以配置读写或者只读。
-
-APIv4 权限
-产品 权限
-现货/杠杆 只读查询订单 读写查询订单&下单
-永续合约 只读查询订单 读写查询订单&下单
-交割合约 只读查询订单 读写查询订单&下单
-钱包 只读查询充提划转记录 读写 查询账户记录&资金划转
-提现 只读查询提现记录 读写 查询提现记录&提现
-所有请求方法为 GET 的都是读操作,其他的则是写请求。每个权限组可以设置为禁用、只读或读写。
-
-值得注意的一点是,尽管提现操作组只有一个 API (即 POST /withdrawals ),考虑到一般使用情况, 还是将其从钱包操作里独立成一个权限组,而包括了提现记录的账户转出流水记录查询(即 GET /wallet/withdrawals )还是保留在钱包 API 权限组了。
-
-#APIv4 验签请求接口发送要求
-在官网个人中心申请 APIv4 Key ,并确保该 Key 拥有对应操作的读写权限。
-在发送请求头部传入 KEY ,即 APIv4 密钥对的 Key
-在发送请求头部传入 Timestamp ,即请求发送的时间,格式是秒级精度的 Unix 时间戳。 同时该时间不能与当前时间差距超过 60 秒。
-在发送请求头部传入 SIGN ,即将请求生成签名字符串并用 APIv4 Secret 加密后生成的签名。 签名字符串生成方法参看下节,加密算法为 HexEncode(HMAC_SHA512(secret, signature_string)) , 即通过 HMAC-SHA512 加密算法,将 APIv4 Secret 作为加密密钥,签名字符串作为加密消息, 生成加密结果的 16 进制输出。
-确保发送请求的客户端 IP 地址在所使用的密钥的 IP 地址白名单里。
-#APIv4 签名字符串生成方式
-APIv4 中签名字符串按照如下方式拼接生成:
-
-Request Method + "\n" + Request URL + "\n" + Query String + "\n" + HexEncode(SHA512(Request Payload)) + "\n" + Timestamp
-
-#Request Method
-请求方法,全大写, 如 POST, GET
-
-#Request URL
-请求 URL,不包括服务地址和端口,如 /api/v4/futures/orders
-
-#Query String
-没有使用 URL 编码的请求参数,请求参数在参与计算签名时的顺序一定要保证和实际请求里的顺序一致。 如 status=finished&limit=50 。
-
-如果没有请求参数,使用空字符串 ("")
-
-#HexEncode(SHA512(Request Payload))
-将请求体字符串使用 SHA512 哈希之后的结果。如果没有请求体,使用空字符串的哈希结果,即 cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
-
-#Timestamp
-设置在请求头部 Timestamp 里的值
-
-示例
-
-注:示例中所有的换行都是为了方便显示人为添加的,实际只有示例中的一个 \n 保留
-
-假设使用的 Key 为 key ,Secret 为 secret
-
-查询所有合约订单
- GET /api/v4/futures/orders?contract=BTC_USD&status=finished&limit=50 HTTP/1.1
-签名字符串:
-
- GET\n
- /api/v4/futures/orders\n
- contract=BTC_USD&status=finished&limit=50\n
- cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e\n
- 1541993715
-说明
-
-/api/v4/futures/orders: 请求 URL
-contract=BTC_USD&status=finished&limit=50: 请求参数,与实际请求的顺序完全一致
-请求体为空,使用空字符串的哈希输出
-1541993715: Unix 时间戳
-签名结果
-
-55f84ea195d6fe57ce62464daaa7c3c02fa9d1dde954e4c898289c9a2407a3d6fb3faf24deff16790d726b66ac9f74526668b13bd01029199cc4fcc522418b8a
-
-创建合约委托
- POST /api/v4/futures/orders HTTP/1.1
-
- {"contract":"BTC_USD","type":"limit","size":100,"price":6800,"time_in_force":"gtc"}
-签名字符串:
-
- POST\n
- /api/v4/futures/orders\n
- \n
- ad3c169203dc3026558f01b4df307641fa1fa361f086b2306658886d5708767b1854797c68d9e62fef2f991645aa82673622ebf417e091d0bd22bafe5d956cca\n
- 1541993715
-说明
-
-请求参数为空,使用空字符串
-使用 JSON 序列化之后的字符串的哈希输出
-签名结果
-
-eae42da914a590ddf727473aff25fc87d50b64783941061f47a3fdb92742541fc4c2c14017581b4199a1418d54471c269c03a38d788d802e2c306c37636389f0
-
-# coding: utf-8
-
-# Python 示例验签代码
-
-"""
-本示例仅作为演示签名计算方式使用,推荐使用各语言的 SDK ,因为已经集成了验签规则
-"""
-
-# coding: utf-8
-import time
-import hashlib
-import hmac
-import requests
-import json
-
-def gen_sign(method, url, query_string=None, payload_string=None):
- key = '' # api_key
- secret = '' # api_secret
-
- t = time.time()
- m = hashlib.sha512()
- m.update((payload_string or "").encode('utf-8'))
- hashed_payload = m.hexdigest()
- s = '%s\n%s\n%s\n%s\n%s' % (method, url, query_string or "", hashed_payload, t)
- sign = hmac.new(secret.encode('utf-8'), s.encode('utf-8'), hashlib.sha512).hexdigest()
- return {'KEY': key, 'Timestamp': str(t), 'SIGN': sign}
-
-if __name__ == "__main__":
- host = "https://api.gateio.ws"
- prefix = "/api/v4"
- common_headers = {'Accept': 'application/json', 'Content-Type': 'application/json'}
-
- url = '/futures/orders'
- body = {"contract": "BTC_USD", "size": 100, "price": "30", "tif": "gtc"}
- request_content = json.dumps(body)
- sign_headers = gen_sign('POST', prefix + url, "", request_content)
- sign_headers.update(common_headers)
- print('signature headers: %s' % sign_headers)
- res = requests.post(host + prefix + url, headers=sign_headers, data=request_content)
- print(res.status_code)
- print(res.content)
-#常见问题
-POST /wallet/transfers 的操作记录怎么查询?
-
-通过 POST /wallet/transfers 执行的转账操作,按不同的账户类型,查询入口分在不同的服务地址,包括:
-
-GET /margin/account_book 查询杠杆账户的转入转入历史
-GET /futures/{settle}/account_book?type=dnw 查询永续合约账户的转入转出历史
-GET /delivery/{settle}/account_book?type=dnw 查询交割合约账户的转入转出历史
-杠杆下单怎么操作?
-
-杠杆下单复用了现货下单接口,只需要在 POST /spot/orders 或 POST /spot/batch_orders 时将请求体里的 account 参数设置为 margin 即可
-
-合约操作返回 USER_NOT_FOUND
-
-原因是因为合约账户没有开户,只需要执行一笔账户划转操作即可。注意不同结算币种有不同的合约账户
-
-合约提示 CONTRACT_NOT_FOUND
-
-不同结算币种的合约也是不同的,请确认指定的合约名称是否在对应结算币种支持的合约列表中。即
-
-GET /futures/{settle}/contracts 和 GET /delivery/{settle}/contracts
-
-主子账号的区别
-
-子账号 API Key 不能操作主子账户互转API, 即 POST /wallet/sub_account_transfers
-子账号 API Key 不能使用API进行提现,即 POST /withdrawals
-如果创建子账号时没有开启对应业务的权限,即时子账号 API key 开启了权限,请求也一样会被拒绝
-上面没有我的问题
-
-联系客服咨询具体问题。如果有使用到某一个语言的 SDK ,也可以在相应 SDK 的 github 项目中提交 issue
-
-提交问题的时候,建议至少包含以下信息,可以更快速定位问题:
-
-用户 ID
-原始的请求 URL、请求参数和请求体内容
-使用的 API Key 是实盘还是模拟的,具体的 Key 是什么(不需要提供 Secret)
-编程语言,最好提供一段发送请求的代码片段
-是否使用了 SDK ,如果使用了 SDK ,具体是调用哪个方法
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/gate-websocket.txt b/src/main/java/com/xcong/excoin/modules/gateApi/gate-websocket.txt
deleted file mode 100644
index d763d63..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/gate-websocket.txt
+++ /dev/null
@@ -1,5011 +0,0 @@
-v4.0.0 · Stable
-#Gate Futures WebSocket v4.0.0
-Gate 提供简单而强大的 Websocket API,将 Gate BTCUSDT 永续合约交易状态集成到您的业务或应用程序中。
-
-我们在 Python 和 Golang 中有语言绑定,将来还会有更多!您可以在右侧的深色区域中查看代码示例,并且可以通过右上角的选项卡切换示例的编程语言
-
-#服务地址
-我们提供 BTC/USDT 结算永续合约交易服务器地址,您可以根据自己的情况选择其中之一
-
-#BTC Contract
-地址列表:
-
-线上交易: wss://fx-ws.gateio.ws/v4/ws/btc
-模拟盘交易: wss://fx-ws-testnet.gateio.ws/v4/ws/btc
-#USDT Contract
-地址列表:
-
-线上交易: wss://fx-ws.gateio.ws/v4/ws/usdt
-线上SBE: wss://fx-ws.gateio.ws/v4/ws/usdt/sbe
-模拟盘交易: wss://ws-testnet.gate.com/v4/ws/futures/usdt
-建议使用SBE以获取更快的行情和更小的带宽成本
-
-如果你使用老的服务地址(wss://fx-ws.gateio.ws/v4/ws 或 wss://fx-ws-testnet.gateio.ws/v4/ws), 将默认是 BTC 结算的 websocket 服务.
-
-#变更日志
-2026-04-14
-
-部分频道支持SBE数据推送: futures.trades、futures.obu、futures.book_ticker、futures.tickers、futures.candlesticks、futures.order_book、futures.order_book_update、futures.usertrades、futures.positions、futures.orders。
-具体的使用查看SBE 数据推送章节
-2026-03-30
-
-futures.order_place 下单请求:iceberg 字段说明修正为类型 string(原文档为 int64)、可选(原文档为必填)
-2026-02-09
-
-模拟盘部分频道支持SBE数据推送
-正式环境实装另行同步
-2026-02-04
-
-futures.obu 模拟盘新增立即的首次快照推送,该次快照推送将会在订阅请求的响应之前推送。此行为与之前快照在订阅请求的响应之后推送不同,请注意该行为变更。
-正式环境实装另行同步
-2026-01-07
-
-futures.orders 新增字段 market_order_slip_ratio (市价单的预设滑点比例)
-futures.order_place futures.order_batch_place 入参新增字段market_order_slip_ratio (允许自定义市价单的最大滑点)
-2025-12-09
-
-合约的张数支持小数,所有的推送的张数、成交量等均改为字符串(可能是小数)。
-
-如何对接websocket的小数支持:
-
-在请求链接websocket时,加入:"X-Gate-Size-Decimal": "1" 的header即可,推送的张数、成交量等将会是字符串(可能是小数)。
-如果在链接websocket时,不加入:"X-Gate-Size-Decimal": "1" 的header,推送将保持原始的字段类型(整形)。
-请尽快切换到字符串的推送支持,后续整形的推送将会下线(下线时间会另行通知)。
-如果出现小数的size,用户如果还是在使用整形的推送,那么推送出来的size将会是向下取整,例如1.1、1.5、1.7的size推送出去都将会是1。
-将影响到以下的推送频道,和对应的字段。
-
-频道 字段
-futures.trades size
-futures.tickers total_size
-futures.book_ticker A B
-futures.order_book_update a.s、b.s
-futures.order_book a.s、b.s
-futures.obu size 会有小数
-futures.candlesticks v
-futures.liquidates left、size、 order_size
-futures.public_liquidates size
-futures.contract_stats long_liq_size、short_liq_size、open_interest
-futures.orders iceberg、left、size
-futures.usertrades size
-futures.auto_deleverages position_size、trade_size
-futures.positions size
-futures.autoorders position_size、 trade_size
-将影响到以下的API请求频道,主要涉及张数,成交量等字段。
-
-频道 字段
-futures.order_place size、left
-futures.order_batch_place size
-futures.order_cancel size、left
-futures.order_cancel_cp size、left
-futures.order_amend size、left
-futures.order_list size、left
-futures.order_status size、left
-2025-09-25
-
-新增 仓位 Adl 排名频道 文档
-2025-05-22
-
-新增深度频道V2文档说明
-futures.order_book_update 新增字段 full
-2025-04-25
-
-账户交易API新增通道 futures.order_cancel_ids
-futures.order_book 和 futures.order_book_update 新增深度档位字段 l
-2025-04-18
-
-补充文档代码示例
-2025-03-24
-
-修复了深度频道部分文档的错误描述
-修复了订单频道部分文档的错误描述
-2025-03-21
-
-更新了频道 futures.orders 文档, 新增了 update_id, update_time, biz_info, stop_profit_price 和 stop_loss_price 等字段的说明
-2025-03-12
-
-合约统计信息频道增加 contract 字段
-更新账户交易 API,新增了 x-gate-exptime 字段
-修复了账户交易 API 部分文档描述性错误
-2025-02-19
-
-新增频道 futures.public_liquidates 用于推送合约强平订单的快照信息
-2025-02-10
-
-更新账户交易 API,新增了 x_in_time, x_out_time, conn_trace_id, trace_id 字段
-futures.order_place, futures.order_batch_place, futures.order_cancel, futures.order_cancel_cp 和 futures.order_amend 新增了 x_gate_ratelimit_requests_remain, x_gate_ratelimit_limit 和 x_gat_ratelimit_reset_timestamp 字段
-2024-11-18
-
-在频道 futures.order_book_update 移除 10 档位 1000ms 推送间隔支持
-2023-09-21
-
-在频道futures.trades推送参数中新增is_internal字段
-2023-08-18
-
-添加 WebSocket API 操作
-WebSocket API 允许通过 WebSocket 连接创建、取消、修改、查询订单。
-2023-07-07
-
-在频道futures.order_book_update中添加新的间隔“20ms”,请注意,20ms 的间隔仅支持 20 档位
-2023-06-20
-
-在频道 futures.positions 增加update_id 字段
-2022-12-22
-
-在频道 futures.autoorders 初始结构中添加新字段 auto_size,将字段详细信息添加到 http api
-2022-11-22
-
-在通用的返回结果中添加新字段“time_ms”,以表示创建消息的时间
-2022-08-11
-
-在频道futures.autoorders通知中添加新字段text
-在频道futures.tickers通知中添加新字段low_24h和high_24h
-2022-04-15
-
-在频道futures.balances通知中添加新字段 currency
-2021-03-31
-
-在频道futures.book_ticker和futures.order_book推送中添加毫秒字段t
-2021-03-10
-
-添加新的订单簿频道 futures.book_ticker 以实时推送最佳卖价/买价
-添加新的订单簿频道 futures.order_book_update 以与用户推送订单簿更改 指定更新频率
-添加本地订单簿维护文档
-2021-03-01
-
-在通用的返回结果中添加以_ms结尾的新毫秒精度时间戳
-在futures.book all通知中添加新字段id
-2020-8-08
-
-添加完整代码 demo(golang, python)
-2020-8-07
-
-添加futures.autoorders频道
-2020-7-07
-
-添加futures.order_book频道
-2020-4-30
-
-添加futures.position频道
-2019-11-06
-
-新增 USDT 结算永续合约的 websocket 推送
-为futures.tickers添加volume_24h_base字段、volume_24h_settle字段、volume_24h_quote字段
-删除旧服务器地址(wss://fx-ws.gateio.ws/v4/ws 或 wss://fx-ws-testnet.gateio.ws/v4/ws)
-如果您使用旧的服务器地址(wss://fx-ws.gateio.ws/v4/ws 或 wss://fx-ws-testnet.gateio.ws/v4/ws),我们 将为您使用 BTC 结算永续合约的 websocket 推送
-
-2019-10-22
-
-添加应用层 ping/pong 消息
-2019-04-30
-
-添加index和mark futures.candlesticks 订阅
-为futures.tickers添加funding_rate_indicative字段
-为futures.orders添加 is_reduce_only 和状态字段
-2019-02-13
-
-更改 webSocket 基本 url
-为futures.tickers添加volume_24h_usd字段和volume_24h_btc字段
-2019-01-11
-
-添加futures.position_closes 和 futures.balance 订阅
-删除频道 futures.auto_deleverages 和futures.liquidates的 finish_time 字段
-为频道 futures.auto_deleverages 和futures.liquidates 添加 time字段
-WebSocket 应用示例
-
-# !/usr/bin/env python
-# coding: utf-8
-
-import hashlib
-import hmac
-import json
-import logging
-import time
-import threading
-
-from websocket import WebSocketApp
-
-logging.basicConfig(level=logging.INFO)
-logger = logging.getLogger(__name__)
-
-event = threading.Event()
-
-class GateWebSocketApp(WebSocketApp):
-
- def __init__(self, url, api_key, api_secret, **kwargs):
- super(GateWebSocketApp, self).__init__(url, **kwargs)
- self._api_key = api_key
- self._api_secret = api_secret
-
- def _send_ping(self):
- while not event.wait(10):
- self.last_ping_tm = time.time()
- if self.sock:
- try:
- self.sock.ping()
- except Exception as ex:
- logger.warning("send_ping routine terminated: {}".format(ex))
- break
- try:
- self._request("futures.ping", auth_required=False)
- except Exception as e:
- raise e
-
- def _request(self, channel, event=None, payload=None, auth_required=True):
- current_time = int(time.time())
- data = {
- "time": current_time,
- "channel": channel,
- "event": event,
- "payload": payload,
- }
- if auth_required:
- message = 'channel=%s&event=%s&time=%d' % (channel, event, current_time)
- data['auth'] = {
- "method": "api_key",
- "KEY": self._api_key,
- "SIGN": self.get_sign(message),
- }
- data = json.dumps(data)
- logger.info('request: %s', data)
- self.send(data)
-
- def get_sign(self, message):
- h = hmac.new(self._api_secret.encode("utf8"), message.encode("utf8"), hashlib.sha512)
- return h.hexdigest()
-
- def subscribe(self, channel, payload=None, auth_required=True):
- self._request(channel, "subscribe", payload, auth_required)
-
- def unsubscribe(self, channel, payload=None, auth_required=True):
- self._request(channel, "unsubscribe", payload, auth_required)
-
-
-def on_message(ws, message):
- # type: (GateWebSocketApp, str) -> None
- # handle message received
- logger.info("message received from server: {}".format(message))
-
-
-def on_open(ws):
- # type: (GateWebSocketApp) -> None
- # subscribe to channels interested
- logger.info('websocket connected')
- ws.subscribe("futures.tickers", ['BTC_USDT'], False)
-
-# custom header
-custom_headers = {
- "X-Gate-Size-Decimal": "1"
-}
-
-if __name__ == "__main__":
- logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.DEBUG)
- app = GateWebSocketApp("wss://fx-ws.gateio.ws/v4/ws/usdt",
- "YOUR_API_KEY",
- "YOUR_API_SECRET",
- on_open=on_open,
- on_message=on_message,
- header=custom_headers)
- app.run_forever(ping_interval=5)
-Copy
-#Websocket API 概述
-#事件
-每个通用 订阅频道/channel(例如ticker、order_book等)都支持一些不同的事件消息,它们是:
-
-subscribe (推荐使用)
-
-订阅,接受服务器的新数据通知。
-
-unsubscribe
-
-如果取消订阅,服务器将不会发送新数据通知。
-
-update
-
-服务器将向客户端发送新的订阅数据(增量数据)。
-
-all
-
-如果有新订阅的数据(所有数据)可用,服务器将向客户端发送通知。
-
-#请求
-每个请求都遵循通用格式,其中包含time、channel、event和payload。
-
-请求
-名称 类型 必选 描述
-id Integer 否 可选的请求 ID,将由服务器发回,以帮助您识别服务器响应哪个请求
-time Integer 是 请求时间
-channel String 是 请求 subscribe/unsubscribe 频道
-auth String 否 请求身份验证信息,请参阅身份验证部分了解详细信息
-event String 是 请求event (subscribe/unsubscribe/update/all/api)
-payload Array 是 请求详细参数
-#响应
-与请求类似,响应遵循以下通用格式,其中包含: time, channel, event , error 和 result.
-
-响应
-名称 类型 必选 描述
-time Integer 是 响应时间
-time_ms Integer 是 毫秒响应时间
-channel String 是 响应频道
-event String 是 响应频道事件 (update/all)
-error Object 是 响应错误
-result Any 是 返回来自服务端的新数据通知 或 对客户端请求的响应。如果有错误返回则error 不为空,没有错误则此字段为空。
-注意:如果它是服务端发起的数据更新通知 那么 result 的类型是基于 channel 的,不同 channel 的 result 类型有所不同。
-
-但如果是对客户端订阅请求的响应,那么 result 为固定的 {"status": "success"}。 验证订阅请求是否成功,您只需要检查 error 字段是否为空即可,不需要再解析 result 字段。
-
-为了简单起见,下面的频道(channel)描述只给出对应频道的 payload 格式。
-
-#错误
-如果出现错误,您会收到error字段,其中包含错误代码和错误的类型。
-
-错误
-Code Message
-1 invalid argument struct
-2 invalid argument
-3 service error
-4 authentication fail
-#鉴权
-如果频道是私有的,则请求体需要携带认证信息, 例如futures.usertrades
-
-WebSocket 认证使用与 HTTP API 相同的签名计算方法,但具有 以下差异:
-
-签名字符串拼接方式:channel=<channel>&event=<event>&time=<time>, 其中<channel>、<event>、<time>是对应的请求信息
-身份验证信息在请求正文中的auth字段中发送。
-您可以登录账户获取永续合约账户的 api_key 和 secret。
-
-名称 类型 描述
-method String 验证方式:api_key
-KEY String apiKey 的值
-SIGN String 签名结果
-代码示例
-
-# example WebSocket signature calculation implementation in Python
-import hmac, hashlib, json, time
-
-
-def gen_sign(channel, event, timestamp):
- # GateAPIv4 key pair
- api_key = 'YOUR_API_KEY'
- api_secret = 'YOUR_API_SECRET'
-
- s = 'channel=%s&event=%s&time=%d' % (channel, event, timestamp)
- sign = hmac.new(api_secret.encode('utf-8'), s.encode('utf-8'), hashlib.sha512).hexdigest()
- return {'method': 'api_key', 'KEY': api_key, 'SIGN': sign}
-
-
-request = {
- 'id': int(time.time() * 1e6),
- 'time': int(time.time()),
- 'channel': 'futures.orders',
- 'event': 'subscribe',
- 'payload': ["20011", "BTC_USD"]
-}
-request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
-print(json.dumps(request))
-Copy
-#SBE 数据推送
-#对接SBE
-使用地址,在现有的地址后添加/sbe:
-prod: wss://fx-ws.gateio.ws/v4/ws/usdt/sbe
-testnet: wss://ws-testnet.gate.com/v4/ws/futures/usdt/sbe
-schema地址:
-prod: gate_fex_ws_prod_latest.xml(opens new window)
-testnet: gate_fex_ws_testnet_latest.xml(opens new window)
-如果需要指定sbe_schema_id,则通过query的形式传入sbe_schema_id的参数,例如:wss://fx-ws.gateio.ws/v4/ws/usdt/sbe?sbe_schema_id=1
-目前支持的sbe_schema_id为0和1;sbe_schema_id为0用于客户端测试sbe schema不兼容升级的逻辑
-不传入sbe_schema_id则默认使用最新的schema版本
-传入不合法的sbe_schema_id在连接之后会返回系统通知,并将sbe_schema_id调整为最新的schema版本
-传入旧版本的sbe_schema_id在连接之后会返回系统通知,提醒更新新版本的SBE schema,依旧使用客户端指定的旧版本schema
-无效的sbe_schema_id的系统通知
-
-{
- "time": 1770600979,
- "time_ms": 1770600979609,
- "channel": "futures.system",
- "event": "update",
- "result": {
- "type": "invalid_sbe_schema_id",
- "msg": "Your sbe_schema_id '011' does not exist, it has been adjusted to the default sbe_schema_id '1'."
- }
-}
-Copy
-过时的sbe_schema_id的系统通知
-
-{
- "time": 1770601096,
- "time_ms": 1770601096665,
- "channel": "futures.system",
- "event": "update",
- "result": {
- "type": "outdated_sbe_schema_id",
- "msg": "Your sbe_schema_id '0' is outdated, please upgrade to the latest version '1'."
- }
-}
-Copy
-#SBE使用说明
-使用JSON进行请求和首次响应;使用SBE作为数据推送;
-同一条连接上同时存在JSON和SBE的消息,请使用opcode来区分数据:opcode为1代表JSON,opcode为2代表SBE。
-SBE 的解码:
-MessageHeader:每条 SBE 二进制帧均为「MessageHeader + 消息体」。Header 中包含 blockLength、templateId、schemaId、version,解码时必须先读 Header,再根据 schemaId 和 templateId 选择对应 Schema 与消息类型解码消息体。
-解码流程建议:
-读取 MessageHeader(固定长度),得到 schemaId、templateId、blockLength、version。
-根据 schemaId 选择解码器:0 → 使用旧版本进行解码;1 → 使用新版本进行解码。
-根据 templateId 确定具体消息类型(如 PublicTrade、OrderBook、Bbo 等),再按该 Schema 的布局解码消息体。
-使用 SBE 时,仅可订阅以下频道,其余频道不支持 SBE 推送。后续将扩展到其余频道。
-订阅不支持SBE的频道时,将返回订阅失败的消息
-通道名 说明
-futures.trades 公共成交
-futures.order_book 订单簿(深度)
-futures.order_book_update 订单簿增量更新
-futures.book_ticker 最优买卖(BBO)
-futures.obu 订单簿增量(OBU)
-futures.candlesticks K 线
-futures.tickers 行情
-futures.usertrades 用户成交
-futures.positions 持仓
-futures.orders 订单
-不支持sbe将返回订阅失败:
-
-{
- "time": 1770603321,
- "time_ms": 1770603321767,
- "conn_id": "57a8765578ea837e",
- "trace_id": "3c75ba05569b3b292a2f36cfdd90d868",
- "channel": "futures.autoorders",
- "event": "subscribe",
- "payload": [
- "15760812",
- "!all"
- ],
- "error": {
- "code": 2,
- "message": "channel futures.autoorders does not support SBE"
- },
- "result": {
- "status": "fail"
- }
-}
-Copy
-#System API
-提供系统状态检查,如 ping/pong.
-
-#Ping/Pong
-检查服务器/客户端连接.
-
-Gate websocket 使用协议层 ping/pong 消息。服务器会发起 ping 操作。如果客户端没有回复,客户端将被断开。
-
-websocket rfc 协议(opens new window)
-
-如果想主动检测连接状态,可以发送应用层 ping 消息,并接收 pong 消息。
-
-#请求参数
-频道
-
-futures.ping
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.ping"}')
-print(ws.recv())
-Copy
-futures.ping操作返回 JSON 结构如下:
-
-{
- "time": 1545404023,
- "time_ms": 1545404023123,
- "channel": "futures.pong",
- "event": "",
- "result": null
-}
-Copy
-#服务升级通知
-服务在即将关闭进行升级时,会向当前连接主动推送一条系统通知,客户端收到后应尽快重连。
-
-服务端推送格式(SystemNotifyDTO):
-
-字段 类型 说明
-type String 通知类型,如 upgrade
-msg String 提示文案
-data Object 可选,扩展数据
-示例(服务升级):
-
-{
- "type": "upgrade",
- "msg": "The connection will soon be closed for a service upgrade. Please reconnect."
-}
-#ticker 频道
-ticker是合约状态的高级概述。它向你展示了最高的, 最低的、最后的交易价格。它还包括每日交易量和价格等信息
-
-#订阅操作
-订阅永续合约 24hr 价格变动情况.
-
-#请求参数
-channel
-
-futures.tickers
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-payload Array 是 合约列表
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.tickers","event": "subscribe", "payload" : ["BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的订阅请求返回 JSON 结构如下:
-
-{
- "time": 1545404023,
- "time_ms": 1545404023123,
- "channel": "futures.tickers",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#ticker 推送
-永续合约 24hr 价格变动情况推送
-
-#推送参数
-channel
-
-futures.tickers
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-contract String 合约名称
-last String 最新成交价
-change_percentage String 涨跌幅
-funding_rate String 资金费率
-funding_rate_indicative String 下一周期预测资金费率(已弃用,改用funding_rate)
-mark_price String 标记价格
-index_price String 指数价格
-total_size String 总数量
-volume_24h String 24 小时成交量
-quanto_base_rate String 双币种合约中基础货币与结算货币的汇率。不存在于其他类型的合同中
-volume_24h_btc String 近 24 小时 BTC 交易量(已弃用,请使用volume_24h_base、volume_24h_quote、volume_24h_settle代替)
-volume_24h_usd String 近 24 小时美元交易量(已弃用,请使用volume_24h_base、volume_24h_quote、volume_24h_settle 代替)
-volume_24h_quote String 近 24 小时交易量,以计价货币计
-volume_24h_settle String 近 24 小时交易量,以结算货币计
-volume_24h_base String 近 24 小时交易量,以基础货币计
-low_24h String 近 24 小时最低交易价
-high_24h String 近 24 小时最高交易价
-{
- "time": 1541659086,
- "time_ms": 1541659086123,
- "channel": "futures.tickers",
- "event": "update",
- "result": [
- {
- "contract": "BTC_USD",
- "last": "118.4",
- "change_percentage": "0.77",
- "funding_rate": "-0.000114",
- "funding_rate_indicative": "0.01875",
- "mark_price": "118.35",
- "index_price": "118.36",
- "total_size": "73648",
- "volume_24h": "745487577",
- "volume_24h_btc": "117",
- "volume_24h_usd": "419950",
- "quanto_base_rate": "",
- "volume_24h_quote": "1665006",
- "volume_24h_settle": "178",
- "volume_24h_base": "5526",
- "low_24h": "99.2",
- "high_24h": "132.5"
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅
-
-#请求参数
-channel
-
-futures.tickers
-
-event
-
-unsubscribe
-
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": 123456,
- "channel": "futures.tickers",
- "event": "unsubscribe",
- "payload": ["BTC_USD"]
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545404900,
- "time_ms": 1545404900123,
- "channel": "futures.tickers",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#公有成交频道
-每当 Gate 发生交易时,该频道都会发送交易消息。它包括价格、金额、时间和类型等交易信息
-
-#公有成交订阅
-订阅公有成交更新通知
-
-#请求参数
-channel
-
-futures.trades
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-payload Array 是 合约列表
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.trades","event": "subscribe", "payload" : ["BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545405058,
- "time_ms": 1545405058123,
- "channel": "futures.trades",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#公有成交推送
-通知最新交易更新
-
-#推送参数
-channel
-
-futures.trades
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-contract string 合约名称
-size string/int 交易数量
-id int 交易 ID
-create_time int 交易消息创建时间
-create_time_ms int 交易消息创建时间(以毫秒为单位)
-price string 交易价格
-is_internal bool 是否为内部成交。内部成交是指保险资金和 ADL 用户对强平指令的接管。由于不是市场深度上的正常撮合,交易价格可能会出现偏差,不会记录在 K 线上。如果不是内部交易,则该字段不会被返回。
-size 正数表示买家,负数表示卖家
-
-{
- "channel": "futures.trades",
- "event": "update",
- "time": 1541503698,
- "time_ms": 1541503698123,
- "result": [
- {
- "size": "-108",
- "id": 27753479,
- "create_time": 1545136464,
- "create_time_ms": 1545136464123,
- "price": "96.4",
- "contract": "BTC_USD",
- "is_internal": true
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅公有成交更新通知
-
-#请求参数
-channel
-
-futures.trades
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send(
- '{"time" : 123456, "channel" : "futures.trades", "event": "subscribe", "payload" : ["BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545404900,
- "time_ms": 1545404900123,
- "channel": "futures.trades",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#深度频道
-order_book 频道允许您跟踪 Gate 订单簿深度的状态。它以价格聚合的方式提供,可自定义精度。
-
-共有三种不同的订单簿渠道可供订阅:
-
-futures.order_book
-
-全量频道,定期使用all推送完整的有限级别订单簿.
-
-futures.book_ticker
-
-实时推送最佳买价和卖价.
-
-futures.order_book_update
-
-以指定的更新频率向用户订单簿推送订单簿的更新内容.
-
-不建议通过futures.order_book接收订单簿更新,使用 futures.order_book_update 可以以更少的流量提供更及时的更新
-
-如何维护本地订单簿:
-
-订阅 futures.order_book_update 并指定级别和更新频率,例如 ["BTC_USDT", "100ms", "100"] 每 100ms 推送 BTC_USDT 订单簿前 100 个级别的更新
-缓存 WebSocket 通知。每个通知都使用“U”和“u”来告诉第一个和最后一个 自上次通知以来更新 ID。
-使用 REST API 检索基本订单簿,并确保记录了订单簿 ID(参考 如下面的“baseID”) 例如https://api.gateio.ws/api/v4/futures/usdt/order_book?contract=BTC_USDT&limit=10&with_id=true 获取 BTC_USDT 的 10 级基础订单簿
-迭代缓存的 WebSocket 通知,找到第一个包含 baseID 的通知, 即 U <= baseId+1 和 u >= baseId+1,然后开始从中消费。请注意,size为 通知都是全量的 size,即应该使用它们覆盖替换原始的size。 如果 size 等于 0,则从订单簿中删除价格。
-转储所有满足 u < baseID+1 的通知。如果 baseID+1 < 第一个通知 U,则 意味着当前的基本订单簿落后于通知。从步骤 3 开始检索更新的内容基本订单簿。
-如果后续发现满足 U > baseID+1 的通知,则说明有更新 丢失的。从步骤 3 重建本地订单簿。
-注意:
-
-即使 WebSocket 推送中的 a, b 或者 asks, bids 为空,用户也需要更新本地订单簿的 id 和 timestamp,以确保本地订单簿与服务器保持一致。
-WebSocket 订阅的 level(档位数)应与 REST 快照的 limit 一致,否则可能导致增量更新无法覆盖快照档位,造成本地订单簿错位或不完整。
-#深度全量更新频道
-订阅深度.
-
-#请求参数
-channel
-
-futures.order_book
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-contract String 是 合约名称
-limit String 是 深度层级: 100, 50, 20, 10, 5, 1
-interval String 是 价格合并精度: "0"
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.order_book","event": "subscribe", "payload" : ["BTC_USD", "20", "0"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545405058,
- "time_ms": 1545405058123,
- "channel": "futures.order_book",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#全量深度推送
-全量深度更新推送
-
-#推送参数
-channel
-
-futures.order_book
-
-event
-
-all
-
-params
-
-推送参数
-名称 类型 描述
-result object 深度信息
-»t Integer 深度生成时间戳(以毫秒为单位)
-»contract String 合约名称
-»id Integer 深度 ID
-»asks Array 深度卖方的档位列表
-»»p String 档位价格
-»»s String 档位的数量
-»bids Array 深度买方的档位列表
-»»p String 档位价格
-»»s String 档位的数量
-»l String 深度层级(例如 100 即代表 100 层的深度更新)
-{
- "channel": "futures.order_book",
- "event": "all",
- "time": 1541500161,
- "time_ms": 1541500161123,
- "result": {
- "t": 1541500161123,
- "contract": "BTC_USD",
- "id": 93973511,
- "asks": [
- {
- "p": "97.1",
- "s": "2245"
- },
- {
- "p": "97.1",
- "s": "2245"
- }
- ],
- "bids": [
- {
- "p": "97.1",
- "s": "2245"
- },
- {
- "p": "97.1",
- "s": "2245"
- }
- ],
- "l": "20"
- }
-}
-Copy
-#全量深度取消订阅
-取消订阅指定市场的深度
-
-#请求参数
-channel
-
-futures.order_book
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.order_book","event": "unsubscribe", "payload" : ["BTC_USD", "20", "0"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545445847,
- "time_ms": 1545445847123,
- "channel": "futures.order_book",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#最佳买卖价订阅
-订阅深度最佳买卖价
-
-#请求参数
-channel
-
-futures.book_ticker
-
-event
-
-subscribe
-
-params
-
-payload是一个包含合约市场的列表.
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.book_ticker","event": "subscribe", "payload" : ["BTC_USDT"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545405058,
- "time_ms": 1545405058123,
- "channel": "futures.book_ticker",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#最佳买卖价的推送
-如果 a 为空字符串,则表示空买价;如果 b 为空字符串,则表示空卖价。
-
-最新买卖价的推送
-
-#推送参数
-channel
-
-futures.book_ticker
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result object 深度的最佳买卖价
-»t Integer 最佳买卖价行情生成的时间戳(以毫秒为单位)
-»u Integer 深度的 ID
-»s String 合约名称
-»b String 最佳买方的价格,如果没有买方,则为空串
-»B String/Integer 最佳买方的数量,如果没有买方,则为 0
-»a String 最佳卖方的价格,如果没有卖方,则为空串
-»A String/Integer 最佳卖方的数量,如果没有卖方,则为 0
-{
- "time": 1615366379,
- "time_ms": 1615366379123,
- "channel": "futures.book_ticker",
- "event": "update",
- "result": {
- "t": 1615366379123,
- "u": 2517661076,
- "s": "BTC_USD",
- "b": "54696.6",
- "B": "37000",
- "a": "54696.7",
- "A": "47061"
- }
-}
-Copy
-#最佳买卖价的取消订阅
-取消指定合约市场的最佳买卖订阅
-
-#请求
-channel
-
-futures.book_ticker
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.book_ticker","event": "unsubscribe", "payload" : ["BTC_USDT"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545445847,
- "time_ms": 1545445847123,
- "channel": "futures.book_ticker",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#合约深度更新推送订阅
-订阅深度更新推送
-
-#请求参数
-channel
-
-futures.order_book_update
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-contract String 是 合约名称
-frequency String 是 更新频率,20ms or 100ms
-level String 否 可选的深度层级。允许以下层级:100、50、20;20ms频率 只支持 20层
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.order_book_update","event": "subscribe", "payload" : ["BTC_USDT", "100ms", "100"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545405058,
- "time_ms": 1545405058123,
- "channel": "futures.order_book_update",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#深度更新推送
-深度更新推送
-
-#推送参数
-channel
-
-futures.order_book_update
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Object 自上次更新以来发生变更要价和出价
-»t Integer 订单簿生成时间戳(以毫秒为单位)
-»full Boolean true 代表全量的深度(假设订阅 level 为 100,推送出来则是 100 层的深度);用户接收到之后需要替换本地深度;false 代表增量的深度,为 false 时,不传输该字段
-»s String 合约名称
-»U Integer 本次更新开始的订单簿更新 ID
-»u Integer 本次更新结束的订单簿更新 ID
-»b Array 买方变动列表
-»»p String 变更的档位价格
-»»s String/Integer 档位的待成交数量。如果为 0,则从订单簿中删除该价格
-»a Array 卖方变动列表
-»»p String 变更的档位价格
-»»s String/Integer 档位的待成交数量。如果为 0,则从订单簿中删除该价格
-»l String 深度层级(例如 100 即代表 100 层的深度更新)
-{
- "time": 1615366381,
- "time_ms": 1615366381123,
- "channel": "futures.order_book_update",
- "event": "update",
- "result": {
- "t": 1615366381417,
- "s": "BTC_USD",
- "U": 2517661101,
- "u": 2517661113,
- "b": [
- {
- "p": "54672.1",
- "s": "0"
- },
- {
- "p": "54664.5",
- "s": "58794"
- }
- ],
- "a": [
- {
- "p": "54743.6",
- "s": "0"
- },
- {
- "p": "54742",
- "s": "95"
- }
- ],
- "l": "100"
- }
-}
-Copy
-#深度更新取消订阅
-取消指定合约的市场的深度更新订阅
-
-#请求参数
-channel
-
-futures.order_book_update
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send(
- '{"time" : 123456, "channel" : "futures.order_book_update", "event": "unsubscribe", "payload" : ["BTC_USDT", "100ms"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545445847,
- "time_ms": 1545445847123,
- "channel": "futures.order_book_update",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#深度频道V2
-提供一种更快更新的获取深度信息的方法.
-
-#维护本地深度
-说明:
-
-全量深度推送(full=true): 当频道推送的深度为全量深度时,需要将该深度数据完整替换本地深度,并将深度ID更新为消息中的字段 u。服务端可能会重复推送全量深度。
-订阅该频道时,首次推送为全量深度。
-增量深度推送(full=false): 增量消息中不会显示 full 字段,此时消息包含字段 U(深度起始ID)和 u(深度结束ID)。
-如果 U = 本地深度ID + 1,则表示深度连续更新:
-将本地深度ID替换为消息中的 u。
-若更新中的 a 和 b 不为空,分别按价格更新对应的买、卖深度数量(level[0] 为价格,level[1] 为数量)。当数量 level[1]= "0" 时,需移除对应档位。
-若 U ≠ 本地深度ID + 1,则深度数据不连续,需要取消订阅该市场,并重新订阅以获取初始化深度。
-订阅限制: 针对同一合约的同一深度流,一个链接只允许订阅一次,重复订阅会返回错误。失败示例:
-{
- "time": 1747391482,
- "time_ms": 1747391482960,
- "id": 1,
- "conn_id": "d9db9373dc5e081e",
- "trace_id": "ee001938590e183db957bd5ba71651c0",
- "channel": "futures.obu",
- "event": "subscribe",
- "payload": [
- "ob.BTC_USDT.400"
- ],
- "error": {
- "code": 2,
- "message": "Alert sub ob.BTC_USDT.400"
- },
- "result": {
- "status": "fail"
- }
-}
-Copy
-#深度频道V2订阅
-#请求参数
-channel
-
-futures.obu
-
-event
-
-subscribe
-
-params
-
-payload是一个包含流名称的列表. 格式为: ob.{symbol}.{level}; 例如 ob.BTC_USDT.400、ob.BTC_USDT.50
-
-其中level枚举为:400、50;更新频率: 400档为100ms;50档为20ms;
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.obu",
- "event": "subscribe", "payload" : ["ob.BTC_USDT.400"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1747391482,
- "time_ms": 1747391482384,
- "id": 1,
- "conn_id": "d9db9373dc5e081e",
- "trace_id": "ee001938590e183db957bd5ba71651c0",
- "channel": "futures.obu",
- "event": "subscribe",
- "payload": [
- "ob.BTC_USDT.400"
- ],
- "result": {
- "status": "success"
- }
-}
-Copy
-#深度v2订阅推送
-深度频道V2的消息推送
-
-#推送参数
-channel
-
-futures.obu
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Object 自上次更新以来发生变更要价和出价
-»t Integer 订单簿生成时间戳(以毫秒为单位)
-»full Boolean true 代表全量的深度;false 代表增量的深度,为 false 时,不传输该字段
-»s String 深度流的名称
-»U Integer 本次更新开始的订单簿更新 ID
-»u Integer 本次更新结束的订单簿更新 ID
-»b Array[OrderBookArray] 自上次更新以来的 bids 更新
-»» OrderBookArray Array[String] [Price, Amount] 数组对, Amount=0应当从本地深度中移除
-»a Array[OrderBookArray] 自上次更新以来的 asks 更新
-»» OrderBookArray Array[String] [Price, Amount] 数组对, Amount=0应当从本地深度中移除
-全量推送示例:
-
-{
- "channel": "futures.obu",
- "result": {
- "t": 1743673026995,
- "full": true,
- "s": "ob.BTC_USDT.400",
- "u": 79072179673,
- "b": [
- ["83705.9", "30166"]
- ],
- "a": [
- ["83706", "4208"]
- ]
- },
- "time_ms": 1743673026999
-}
-Copy
-增量推送示例:
-
-{
- "channel": "futures.obu",
- "result": {
- "t": 1743673027017,
- "s": "ob.BTC_USDT.400",
- "U": 79072179674,
- "u": 79072179694,
- "b": [
- ["83702.2", "62"],
- ["83702.1", "0"],
- ["83702", "0"],
- ["83685.6", "120"],
- ["83685", "239"]
- ]
- },
- "time_ms": 1743673027020
-}
-Copy
-#深度频道V2取消订阅
-取消指定合约的市场的深度频道V2订阅
-
-#请求参数
-channel
-
-futures.obu
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send(
- '{"time" : 123456, "channel" : "futures.obu", "event": "unsubscribe", "payload" : ["ob.BTC_USDT.400"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1743673617,
- "time_ms": 1743673617242,
- "id": 1,
- "conn_id": "7b06ff199a98ab0e",
- "trace_id": "8f86e4021a84440e502f73fde5b94918",
- "channel": "futures.obu",
- "event": "unsubscribe",
- "payload": ["ob.BTC_USDT.400"],
- "result": {
- "status": "success"
- }
-}
-Copy
-#K 线频道
-提供一种访问 K 线信息的方法.
-
-#K 线订阅
-如果在contract前面加上mark_,则将订阅合约的标记价格 K 线;如果 前缀为“index_”,将订阅指数价格 K 线.
-
-#请求参数
-channel
-
-futures.candlesticks
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 描述
-interval String Interval : "10s", "1m", "5m", "15m", "30m", "1h", "4h", "8h", "1d", "7d"
-contract String 合约名称
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.candlesticks","event": "subscribe", "payload" : ["1m", "BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545445847,
- "time_ms": 1545445847123,
- "channel": "futures.candlesticks",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#k 线消息推送
-k 线的消息推送
-
-#推送参数
-channel
-
-futures.candlesticks
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-t Integer 时间
-o String 开盘价格
-c String 收盘价格
-h String 最高价格
-l String 最低价格
-v String/Integer 成交量
-n String 合约名称
-a String 成交原始币种数量
-w Boolean true 表示窗口已关闭。注:可能会缺失 true 的消息,但不影响数据的完整性
-{
- "time": 1542162490,
- "time_ms": 1542162490123,
- "channel": "futures.candlesticks",
- "event": "update",
- "result": [
- {
- "t": 1545129300,
- "v": "27525555",
- "c": "95.4",
- "h": "96.9",
- "l": "89.5",
- "o": "94.3",
- "n": "1m_BTC_USD",
- "a": "314732.87412",
- "w": false
- },
- {
- "t": 1545129300,
- "v": "27525555",
- "c": "95.4",
- "h": "96.9",
- "l": "89.5",
- "o": "94.3",
- "n": "1m_BTC_USD",
- "a": "314732.87412",
- "w": true
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅指定市场 K 线信息
-
-#请求参数
-channel
-
-futures.candlesticks
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send(
- '{"time" : 123456, "channel" : "futures.candlesticks", "event": "unsubscribe", "payload" : ["1m", "BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545445847,
- "time_ms": 1545445847123,
- "channel": "futures.candlesticks",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#公共强平订单频道
-提供一种接收Gate强平订单信息的方式,每个合约每1秒最多推一条强平订单数据
-
-#公共强平订单订阅
-如果您想订阅所有合约中的强平订单推送,请在订阅请求列表中使用 !all
-
-订阅公共强平订单推送
-
-#请求参数
-channel
-
-futures.public_liquidates
-
-event
-
-subscribe
-
-params
-
-名称 类型 必选 描述
-contract String 是 合约名称列表
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": 123456,
- "channel": "futures.public_liquidates",
- "event": "subscribe",
- "payload": ["BTC_USD","ETH_USD"],
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.public_liquidates",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#公共强平订单推送
-推送公共强制平仓更新
-
-#推送参数
-channel
-
-futures.public_liquidates
-
-event
-
-update
-
-params
-
-名称 类型 描述
-result Array Array of objects
-名称 类型 描述
-price Float 订单价格
-size String/Integer 强平订单数量
-time_ms Integer 时间(以毫秒为单位)
-contract String 合约名称
-{
- "channel": "futures.public_liquidates",
- "event": "update",
- "time": 1541505434,
- "time_ms": 1541505434123,
- "result": [
- {
- "price": 215.1,
- "size": "-124",
- "time_ms": 1541486601123,
- "contract": "BTC_USD",
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅公共强平订单更新
-
-#请求参数
-channel
-
-futures.public_liquidates
-
-event
-
-unsubscribe
-
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": 123456,
- "channel": "futures.public_liquidates",
- "event": "unsubscribe",
- "payload": ["BTC_USD"],
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
- {
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.public_liquidates",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#合约统计信息频道
-contract_stats 通道允许您获取合约统计信息
-
-#订阅操作
-订阅合约统计信息
-
-#请求参数
-channel
-
-futures.contract_stats
-
-event
-
-subscribe
-
-params
-
-名称 类型 必选 描述
-contract String Yes 合约名称
-interval String Yes Interval : "1m", "5m", "15m", "30m", "1h", "4h", "8h", "1d", "3d", "7d"
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.contract_stats","event": "subscribe", "payload" : ["BTC_USD","1m"]}')
-print(ws.recv())
-Copy
-上面的订阅请求返回 JSON 结构如下:
-
-{
- "time": 1545404023,
- "time_ms": 1545404023123,
- "channel": "futures.contract_stats",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#contract_stats 推送
-合约统计信息推送
-
-#推送参数
-channel
-
-futures.contract_stats
-
-event
-
-update
-
-params
-
-名称 类型 描述
-result Array Array of objects
-名称 类型 描述
-time Integer 统计时间(时间戳)
-contract string 合约名称
-mark_price Float 当前标记价格
-lsr_taker Float 多空吃单比
-lsr_account Float 多空持仓用户比
-long_liq_size string/Integer 做多爆仓量(张)
-long_liq_amount Float 做多爆仓量(交易币种)
-long_liq_usd Float 做多爆仓量(计价币种)
-short_liq_size string/Integer 做空爆仓量(张)
-short_liq_amount Float 做空爆仓量(交易币种)
-short_liq_usd Float 做空爆仓量(计价币种)
-open_interest string/Integer 总持仓量(张)
-open_interest_usd Float 总持仓量(计价币种)
-top_lsr_account Float 大户多空账户比
-top_lsr_size Float 大户多空持仓比
-{
- "time": 1541659086,
- "time_ms": 1541659086123,
- "channel": "futures.contract_stats",
- "event": "update",
- "result": [
- {
- "time": 1603865400,
- "contract":"BTC_USDT",
- "lsr_taker": 100,
- "lsr_account": 0.5,
- "long_liq_size": "0",
- "short_liq_size": "0",
- "open_interest": "124724",
- "short_liq_usd": 0,
- "mark_price": "8865",
- "top_lsr_size": 1.02,
- "short_liq_amount": 0,
- "long_liq_amount": 0,
- "open_interest_usd": 1511,
- "top_lsr_account": 1.5,
- "long_liq_usd": 0
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅
-
-#请求参数
-channel
-
-futures.contract_stats
-
-event
-
-unsubscribe
-
-params
-
-名称 类型 必选 描述
-contract String Yes 合约名称
-interval String Yes Interval : "1m", "5m", "15m", "30m", "1h", "4h", "8h", "1d", "3d", "7d"
-注意:contract为unsub_all,表示全部取消
-
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": 123456,
- "channel": "futures.contract_stats",
- "event": "unsubscribe",
- "payload": ["BTC_USD","1m"]
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的请求返回 JSON 结构如下:
-
-{
- "time": 1545404900,
- "time_ms": 1545404900123,
- "channel": "futures.contract_stats",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#订单频道
-提供接收用户订单的推送
-
-需要认证.
-
-#订单订阅
-如果您想订阅所有合约中的订单更新,请在合约列表中使用 !all。
-
-订阅订单更新推送
-
-#请求参数
-channel
-
-futures.orders
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.orders",
- "event": "subscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.orders",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#订单推送
-下单、更新或完成时通知用户订单信息
-
-#推送参数
-channel
-
-futures.orders
-
-event
-
-update
-
-params
-
-推送结果参数含义请参考http接口.
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-create_time Integer 订单创建时间(已弃用)
-create_time_ms Integer 订单创建时间戳(以毫秒为单位)
-fill_price Float 订单成交价格
-finish_as String 订单是如何完成的。
-- filled:全部成交
-- cancelled:手动取消
-- liquidated:因清算而取消
-- ioc:生效时间为 IOC,立即完成
-- auto_deleveraging:ADL 完成
-- reduce_only:因减仓设置而增仓而取消
-- position_close:因平仓而取消
-- stp:订单发生自成交限制而被撤销
-- _new:新建
-- _update:成交或部分成交或更新订单
-- reduce_out: 只减仓被排除的不容易成交的挂单
-iceberg String/Integer 冰山下单显示的数量,不指定或传 0 都默认为普通下单。目前不支持全部冰山。
-id Integer 订单 ID
-is_close Bool 该订单是否为 close position
-is_liq Bool 该订单是否为 liquidation
-left String/Integer 剩余可交易数量
-mkfr Float Maker 费用
-is_reduce_only Bool 该订单是否为 reduce-only
-status String 订单状态
-- open: 等待交易
-- finished: 完成
-tkfr Float taker 费用
-price Float 订单价格。 0 表示市价订单,tif 设置为 ioc
-refu Integer 推荐用户 ID
-refr Float
-size String/Integer 订单大小。指定正数进行出价,指定负数进行询问
-text String 用户定义的信息
-tif String 有效时间
-- gtc:GoodTillCancelled
-- ioc:ImmediateOrCancelled,仅接受者
-- poc:PendingOrCancelled,只进行后订单,始终享受挂单费用
-- fok: FillOrKill,完全填充或不填充
-type=market 时仅支持 ioc 和 fok
-finish_time Integer 订单结束 unix 时间戳(以秒为单位),未结束订单此字段返回0
-finish_time_ms Integer 订单结束 unix 时间戳(以毫秒为单位),未结束订单此字段返回0
-user String 用户 ID
-contract String 合约名称
-stp_id String 同一 stp_id 组内的用户之间的订单不允许自交易
-1.如果匹配的两个订单的 stp_id 非零且相等,则不会被执行。而是根据 taker 的 stp_act 执行相应的策略。
-2.对于未设置 STP 组的订单,stp_id 默认返回 0
-stp_act String 自我交易预防行动。用户可以通过该字段设置自我交易防范策略
-1.用户加入 STP Group 后,可以通过 stp_act 来限制用户的自我交易防范策略。如果不传 stp_act,则默认为 cn 策略。
-2.当用户没有加入 STP 组时,传递 stp_act 参数时会返回错误。
-3.如果用户下单时没有使用'stp_act','stp_act'将返回'-'
-- cn: 取消最新订单,取消新订单并保留旧订单
-- co: 取消最旧订单,取消旧订单并保留新订单
-- cb:取消两者,新旧订单都会被取消
-amend_text String 用户修改订单时备注的自定义数据
-update_id Integer 更新id
-update_time Integer 更新时间 (毫秒时间戳)
-biz_info String 用户可以备注这次修改的信息
-stop_profit_price String 止盈价格
-stop_loss_price String 止损价格
-market_order_slip_ratio String 该笔市价单的预设的最大滑点比率(不代表实际的滑点),0.03代表3%的最大滑点
-{
- "channel": "futures.orders",
- "event": "update",
- "time": 1541505434,
- "time_ms": 1541505434123,
- "result": [
- {
- "contract": "BTC_USD",
- "create_time": 1628736847,
- "create_time_ms": 1628736847325,
- "fill_price": 40000.4,
- "finish_as": "filled",
- "finish_time": 1628736848,
- "finish_time_ms": 1628736848321,
- "iceberg": "0",
- "id": 4872460,
- "is_close": false,
- "is_liq": false,
- "is_reduce_only": false,
- "left": "0",
- "mkfr": -0.00025,
- "price": 40000.4,
- "refr": 0,
- "refu": 0,
- "size": "1",
- "status": "finished",
- "text": "-",
- "tif": "gtc",
- "tkfr": 0.0005,
- "user": "110xxxxx",
- "update_id": 1,
- "update_time": 1541505434123,
- "stop_loss_price": "",
- "stop_profit_price": "",
- "market_order_slip_ratio": "0.03"
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅订单更新通知
-
-#请求参数
-channel
-
-futures.orders
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.orders",
- "event": "unsubscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.orders",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#用户私有成交频道
-提供接收用户交易的方式
-
-需要认证
-
-#用户私有成交订阅
-如果您想订阅所有的市场交易更新,请在请求参数列表中使用!all。
-
-订阅私有成交更新
-
-#请求参数
-channel
-
-futures.usertrades
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.usertrades",
- "event": "subscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.usertrades",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#用户私有成交推送
-推送用户私有成交更新
-
-#推送参数
-channel
-
-futures.usertrades
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-contract String 合约名称
-create_time Integer 创建时间
-create_time_ms Integer 创建时间(以毫秒为单位)
-id String 交易 ID
-order_id String 订单 ID
-price String 交易价格
-size String/Integer 交易数量
-role String 用户角色 (maker/taker)
-text String 订单自定义信息,用户可以用该字段设置自定义 ID,用户自定义字段必须满足以下条件:
-
-1. 必须以 t- 开头
-2. 不计算 t- ,长度不能超过 28 字节
-3. 输入内容只能包含数字、字母、下划线(_)、中划线(-) 或者点(.)
-
-除用户自定义信息以外,以下为内部保留字段,标识订单来源:
-
-- web: 网页
-- api: API 调用
-- app: 移动端
-- auto_deleveraging: 自动减仓
-- liquidation: 老经典模式仓位强制平仓
-- liq-xxx: a. 新经典模式仓位强制平仓,包含逐仓、单向全仓、双向全仓非对冲仓位强平。 b. 统一账户单币种保证金模式逐仓强制平仓
-- hedge-liq-xxx: 新经典模式双向全仓对冲部分强制平仓,即同时平多空仓位
-- pm_liquidate: 统一账户跨币种保证金模式强制平仓
-- comb_margin_liquidate: 统一账户组合保证金模式强制平仓
-- scm_liquidate: 统一账户单币种保证金模式仓位强制平仓
-- insurance: 保险
-- clear: 合约下架清退
-fee Float 手续费
-point_fee Float 点卡手续费
-{
- "time": 1543205083,
- "time_ms": 1543205083123,
- "channel": "futures.usertrades",
- "event": "update",
- "result": [
- {
- "id": "3335259",
- "create_time": 1628736848,
- "create_time_ms": 1628736848321,
- "contract": "BTC_USD",
- "order_id": "4872460",
- "size": "1",
- "price": "40000.4",
- "role": "maker",
- "text": "api",
- "fee": 0.0009290592,
- "point_fee": 0
- }
- ]
-}
-Copy
-#取消订阅
-取消私有成交订阅
-
-#请求参数
-channel
-
-futures.usertrades
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.usertrades",
- "event": "unsubscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.usertrades",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#强制平仓频道
-提供一种接收用户强制平仓信息的方式
-
-需要认证
-
-#清算订阅
-如果您想订阅所有合约中的强制平仓推送,请在订阅请求列表中使用 !all
-
-订阅用户强制平仓推送
-
-#请求参数
-channel
-
-futures.liquidates
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.liquidates",
- "event": "subscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.liquidates",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#强制平仓推送
-推送强制平仓更新
-
-#推送参数
-channel
-
-futures.liquidates
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-entry_price Float 平均入场价
-fill_price Float 平均执行价格
-leverage Float 杠杆大小
-liq_price Float 清算价格
-margin Float Margin
-mark_price Float 标记价格
-order_id Integer 订单 ID
-order_price Float 订单价格
-left String/Integer 订单未完成数量
-size Integer 原始订单数量
-time Integer 时间
-time_ms Integer 时间(以毫秒为单位)
-user String 用户 ID
-contract String 合约名称
-{
- "channel": "futures.liquidates",
- "event": "update",
- "time": 1541505434,
- "time_ms": 1541505434123,
- "result": [
- {
- "entry_price": 209,
- "fill_price": 215.1,
- "left": 0,
- "leverage": 0.0,
- "liq_price": 213,
- "margin": 0.007816722941,
- "mark_price": 213,
- "order_id": 4093362,
- "order_price": 215.1,
- "size": "-124",
- "time": 1541486601,
- "time_ms": 1541486601123,
- "contract": "BTC_USD",
- "user": "1040xxxx"
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅清算更新
-
-#请求参数
-channel
-
-futures.liquidates
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.liquidates",
- "event": "unsubscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.liquidates",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#自动减仓频道
-提供一种接收用户自动减仓信息的方法
-
-需要认证
-
-#自动减仓订阅
-如果您想订阅所有合约的自动减仓更新,请在请求参数列表中使用!all
-
-订阅用户自动减仓更新
-
-#请求参数
-channel
-
-futures.auto_deleverages
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.auto_deleverages",
- "event": "subscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.auto_deleverages",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#自动减仓推送
-自动减仓消息
-
-#推送参数
-channel
-
-futures.auto_deleverages
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-entry_price Float 入场价格
-fill_price Float 执行价格
-position_size Integer 持仓规模
-trade_size Integer 交易数量
-time Integer 时间
-time_ms Integer 时间(以毫秒为单位)
-user String 用户 ID
-contract String 合约名称
-{
- "channel": "futures.auto_deleverages",
- "event": "update",
- "time": 1541505434,
- "time_ms": 1541505434123,
- "result": [
- {
- "entry_price": 209,
- "fill_price": 215.1,
- "position_size": "10",
- "trade_size": "10",
- "time": 1541486601,
- "time_ms": 1541486601123,
- "contract": "BTC_USD",
- "user": "1040"
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅自动减仓
-
-#请求参数
-channel
-
-futures.auto_deleverages
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.auto_deleverages",
- "event": "unsubscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.auto_deleverages",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#平仓频道
-提供一种接收用户仓位平仓信息的方法
-
-需要认证
-
-#平仓订阅
-如果您想订阅所有合约的平仓更新,请在合约列表中使用 !all
-
-订阅用户平仓信息更新
-
-#请求参数
-channel
-
-futures.position_closes
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.position_closes",
- "event": "subscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.position_closes",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#平仓信息推送
-平仓信息推送
-
-#推送参数
-channel
-
-futures.position_closes
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-contract String 合约名称
-pnl Number 利润损失
-side String 方向 (long or short)
-text String 附带信息
-time Integer 时间
-time_ms Integer 时间(以毫秒为单位)
-user String 用户 ID
-{
- "channel": "futures.position_closes",
- "event": "update",
- "time": 1541505434,
- "time_ms": 1541505434123,
- "result": [
- {
- "contract": "BTC_USD",
- "pnl": -0.000624354791,
- "side": "long",
- "text": "web",
- "time": 1547198562,
- "time_ms": 1547198562123,
- "user": "211xxxx"
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅平仓更新
-
-#请求参数
-channel
-
-futures.position_closes
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.position_closes",
- "event": "unsubscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.position_closes",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#余额频道
-提供一种接收用户余额信息的方法
-
-需要认证
-
-#余额信息订阅
-订阅用户余额更新
-
-#请求参数
-channel
-
-futures.balances
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.balances",
- "event": "subscribe",
- "payload": ["20011"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.balances",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#余额更新推送
-通知余额更新信息
-
-#推送参数
-channel
-
-futures.balances
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-balance Number 余额最终数量
-change Number 余额变化数量
-text String 附带信息
-time Integer 时间
-time_ms Integer 时间(以毫秒为单位)
-type String 变更类型:
-dnw: 出入金
-pnl:盈亏
-refr: 推荐人费用
-fund: 资金费用
-cross_settle: 统一账户结算
-point_dnw: 点卡出入金
-point_fee: 点卡手续费
-point_refr: 点卡推荐人费用
-bonus_dnw: 体验金出入金
-pv_dnw: 仓位体验券充值提现
-fee: 手续费
-user String 用户 ID
-currency String 币种
-{
- "channel": "futures.balances",
- "event": "update",
- "time": 1541505434,
- "time_ms": 1541505434123,
- "result": [
- {
- "balance": 9.998739899488,
- "change": -0.000002074115,
- "text": "BTC_USD:3914424",
- "time": 1547199246,
- "time_ms": 1547199246123,
- "type": "fee",
- "user": "211xxx",
- "currency": "btc"
- }
- ]
-}
-Copy
-#取消订阅
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.balances",
- "event": "unsubscribe",
- "payload": ["20011"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.balances",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#降低风险率频道
-推送用户降低风险率信息
-
-需要认证
-
-#降低风险率订阅
-如果您想订阅所有合约的降低风险率更新,请在合约列表中使用 !all。
-
-订阅用户降低风险率更新
-
-#请求参数
-channel
-
-futures.reduce_risk_limits
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.reduce_risk_limits",
- "event": "subscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.reduce_risk_limits",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#降低风险率推送
-通知降低风险限制更新
-
-#推送参数
-channel
-
-futures.reduce_risk_limits
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-cancel_orders Integer Cancel orders
-contract String 合约名称
-leverage_max Integer 最大杠杆
-liq_price Float 清算价格
-maintenance_rate Float Maintenance rate
-risk_limit Integer 风险限额
-time Integer 时间
-time_ms Integer 时间(以毫秒为单位)
-user String 用户 ID
-{
- "time": 1551858330,
- "time_ms": 1551858330123,
- "channel": "futures.reduce_risk_limits",
- "event": "update",
- "result": [
- {
- "cancel_orders": 0,
- "contract": "ETH_USD",
- "leverage_max": 10,
- "liq_price": 136.53,
- "maintenance_rate": 0.09,
- "risk_limit": 450,
- "time": 1551858330,
- "time_ms": 1551858330123,
- "user": "20011"
- }
- ]
-}
-Copy
-#取消订阅
-退订降低风险限制更新
-
-#请求参数
-channel
-
-futures.reduce_risk_limits
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.reduce_risk_limits",
- "event": "unsubscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-#仓位频道
-提供一种接收用户仓位信息的方法
-
-需要认证
-
-#仓位订阅
-如果您想订阅所有合约的持仓更新,请在合约列表中使用 !all
-
-订阅用户仓位更新
-
-#请求参数
-channel
-
-futures.positions
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-user id String 是 用户 ID (该字段已废弃,仅做占位符使用)
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.positions",
- "event": "subscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.positions",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#仓位信息推送
-推送仓位更新.
-
-#推送参数
-channel
-
-futures.positions
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-contract String 合约名称
-cross_leverage_limit Float 全仓模式下的杠杆倍数
-entry_price Float 开仓价格
-history_pnl Float 已平仓的仓位总盈亏
-history_point Float 已平仓的点卡总盈亏
-last_close_pnl Float 最近一次平仓的盈亏
-leverage Integer 杠杆倍数,0代表全仓,正数代表逐仓
-leverage_max Integer 当前风险限额下,允许的最大杠杆倍数
-liq_price Float 爆仓价格
-maintenance_rate Float 当前风险限额下,维持保证金比例
-margin Float 保证金
-realised_pnl Float 已实现盈亏
-realised_point Float 点卡已实现盈亏
-risk_limit Integer 风险限额
-size String/Integer 合约 size
-time Integer 更新 unix 时间戳
-time_ms Integer 更新 unix 时间戳(以毫秒为单位)
-user String 用户 ID
-update_id Integer 消息序列号,每次推送 order 之后会自增 1
-{
- "time": 1588212926,
- "time_ms": 1588212926123,
- "channel": "futures.positions",
- "event": "update",
- "result": [
- {
- "contract": "BTC_USD",
- "cross_leverage_limit": 0,
- "entry_price": 40000.36666661111,
- "history_pnl": -0.000108569505,
- "history_point": 0,
- "last_close_pnl": -0.000050123368,
- "leverage": 0,
- "leverage_max": 100,
- "liq_price": 0.1,
- "maintenance_rate": 0.005,
- "margin": 49.999890611186,
- "mode": "single",
- "realised_pnl": -1.25e-8,
- "realised_point": 0,
- "risk_limit": 100,
- "size": "3",
- "time": 1628736848,
- "time_ms": 1628736848321,
- "user": "110xxxxx",
- "update_id": 170919
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅仓位更新
-
-#请求参数
-channel
-
-futures.positions
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.positions",
- "event": "unsubscribe",
- "payload": ["20011", "BTC_USD"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.positions",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#仓位 Adl 排名频道
-推送用户仓位 adl 排名信息的频道
-
-需要认证
-
-#仓位 adl 订阅
-如果您想订阅所有合约的 adl 更新,请在合约列表中使用 !all
-
-订阅用户仓位 adl 更新
-
-#请求参数
-channel
-
-futures.position_adl_rank
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://ws-testnet.gate.com/v4/ws/futures/usdt")
-req = {
- "time": int(time.time()),
- "channel": "futures.position_adl_rank",
- "event": "subscribe",
- "payload": ["BTC_USDT"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.position_adl_rank",
- "event": "subscribe",
- "payload": [
- "BTC_USDT"
- ],
- "result": {
- "status": "success"
- }
-}
-Copy
-#仓位 adl 信息推送
-推送仓位更新.
-
-#推送参数
-channel
-
-futures.position_adl_rank
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-contract String 合约名称
-mode String 持仓模式
-rank_division Integer 排名区间(1~6,1为最优先被ADL的区间,5为最靠后被ADL的区间。6:爆仓中不参与ADL排序)
-time_ms Integer 消息推送的毫秒时间戳
-user_id Integer 用户 ID
-{
- "time": 1588212926,
- "time_ms": 1588212926123,
- "channel": "futures.position_adl_rank",
- "event": "update",
- "result": [
- {
- "contract": "BTC_USDT",
- "mode": "single",
- "rank_division": 1,
- "time_ms": 1588212926119,
- "user_id": 2124426495
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅仓位更新
-
-#请求参数
-channel
-
-futures.position_adl_rank
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://ws-testnet.gate.com/v4/ws/futures/usdt")
-req = {
- "time": int(time.time()),
- "channel": "futures.position_adl_rank",
- "event": "unsubscribe",
- "payload": ["BTC_USDT"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.position_adl_rank",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#自动订单频道
-提供一种接收用户自动订单信息的方法
-
-需要认证
-
-#自动订单订阅
-如果您想订阅所有合约中的自动订单更新,请在合约列表中使用!all
-
-订阅用户自动订单更新
-
-#请求参数
-channel
-
-futures.autoorders
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称 类型 必选 描述
-contract String 是 合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.autoorders",
- "event": "subscribe",
- "payload": ["BTC_USDT"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.autoorders",
- "event": "subscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#自动订单消息推送
-通知自动订单更新
-
-#推送参数
-channel
-
-futures.autoorders
-
-event
-
-update
-
-params
-
-推送参数
-名称 类型 描述
-result Array Array of objects
-推送参数
-名称 类型 描述
-user Number 用户 ID
-trigger Object
-initial Object
-id Number 自动订单 ID
-trade_id Number 交易 ID
-status String 订单状态
-reason String 变更原因
-create_time Number 创建时间
-name String 名称
-is_stop_order boolean 是否停止
-stop_trigger Object
-order_type String 止盈/止损类型,详情参见 http api
-me_order_id Number 订单止盈/止损对应订单 ID.
-{
- "time": 1596798126,
- "time_ms": 1596798126123,
- "channel": "futures.autoorders",
- "event": "update",
- "result": [
- {
- "user": 123456,
- "trigger": {
- "strategy_type": 0,
- "price_type": 0,
- "price": "10000",
- "rule": 2,
- "expiration": 86400
- },
- "initial": {
- "contract": "BTC_USDT",
- "size": "10",
- "price": "10000",
- "tif": "gtc",
- "text": "web",
- "iceberg": "0",
- "is_close": false,
- "is_reduce_only": false,
- "auto_size": ""
- },
- "id": 9256,
- "trade_id": 0,
- "status": "open",
- "reason": "",
- "create_time": 1596798126,
- "name": "price_autoorders",
- "is_stop_order": false,
- "stop_trigger": {
- "rule": 0,
- "trigger_price": "",
- "order_price": ""
- },
- "order_type": "close-long-order",
- "me_order_id": "213867453823"
- }
- ]
-}
-Copy
-#取消订阅
-取消订阅自动订单更新
-
-#请求参数
-channel
-
-futures.autoorders
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
- "time": int(time.time()),
- "channel": "futures.autoorders",
- "event": "unsubscribe",
- "payload": ["BTC_USDT"],
- "auth": {
- "method": "api_key",
- "KEY": "xxxx",
- "SIGN": "xxxx"
- }}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
- "time": 1545459681,
- "time_ms": 1545459681123,
- "channel": "futures.autoorders",
- "event": "unsubscribe",
- "result": {
- "status": "success"
- }
-}
-Copy
-#账户交易 API
-#Websocket 交易 API
-WebSocket API 允许通过 WebSocket 连接下单、取消、修改、查询订单.
-
-#Websocket API 客户端请求
-客户端发起的 api 请求遵循通用的 JSON 格式, 包含以下字段:
-
-名称 类型 必选 描述
-time Integer 是 请求时间(以秒为单位)。请求时间和服务器时间之间的差距不得超过 60 秒
-id Integer 否 可选的请求 ID,将由服务器发回,以帮助您识别服务器响应哪个请求
-channel String 是 要访问的 WebSocket 频道
-event String 是 固定为api
-payload Object 是 可选请求详细参数
-»req_id String 是 消息的唯一标识符由客户端提供,将在响应消息中返回,用于标识相应的请求。
-»timestamp String 是 签名时间(秒)
-»api_key String 是 Gate APIv4 APIKey
-»signature String 是 使用 GateAPIv4 密钥和请求信息生成的身份验证签名,
-详细信息请参见[Websocket API 身份验证](#Websocket API 身份验证)部分
-»req_param []Byte 是 请求 api 参数
-请注意,payload.req_param 的类型是与频道(channel字段)绑定的,频道不同payload.req_param 的字段也不同,以 futures.order_place 为例,payload.req_param 与 apiv4 /futures/{settle}/orders (opens new window)。 例如,您可以对 BTC_USDT 下限价单
-
-代码示例
-
-#!/usr/bin/python
-
-import time
-import json
-import hmac
-import hashlib
-import websocket
-import threading
-
-
-API_KEY = "xxxxx"
-SECRET = "xxxxx"
-WS_URL = "wss://fx-ws.gateio.ws/v4/ws/usdt"
-CHANNEL_LOGIN = "futures.login"
-CHANNEL_ORDER_PLACE = "futures.order_place"
-
-def get_ts():
- return int(time.time())
-
-def get_ts_ms():
- return int(time.time() * 1000)
-
-def get_signature(secret, channel, request_param_bytes, ts):
- key = f"api\n{channel}\n{request_param_bytes.decode()}\n{ts}"
- return hmac.new(secret.encode(), key.encode(), hashlib.sha512).hexdigest()
-
-def build_login_request():
- ts = get_ts()
- req_id = f"{get_ts_ms()}-1"
- request_param = b""
-
- sign = get_signature(SECRET, CHANNEL_LOGIN, request_param, ts)
-
- payload = {
- "api_key": API_KEY,
- "signature": sign,
- "timestamp": str(ts),
- "req_id": req_id
- }
-
- return {
- "time": ts,
- "channel": CHANNEL_LOGIN,
- "event": "api",
- "payload": payload
- }
-
-
-def build_order_request():
- ts = get_ts()
- req_id = f"{get_ts_ms()}-2"
- order_param = {
- "contract": "BTC_USDT",
- "size": 6024,
- "iceberg": 0,
- "price": "3765",
- "tif": "gtc",
- "text": "t-my-custom-id",
- "stp_act": "-"
- }
-
-
- payload = {
- "req_id": req_id,
- "req_param": order_param
- }
-
- return {
- "time": ts,
- "channel": CHANNEL_ORDER_PLACE,
- "event": "api",
- "payload": payload
- }
-
-
-def on_message(ws, message):
- print(f"recv: {message}")
-
-def on_error(ws, error):
- print(f"error: {error}")
-
-def on_close(ws, close_status_code, close_msg):
- print("connection closed")
-
-def on_open(ws):
- print("WebSocket opened")
-
- login_payload = build_login_request()
- print("login payload:", login_payload)
- ws.send(json.dumps(login_payload))
-
- def delayed_order():
- time.sleep(2)
- order_payload = build_order_request()
- print("order payload:", order_payload)
- ws.send(json.dumps(order_payload))
-
- threading.Thread(target=delayed_order).start()
-
-custom_headers = {
- "X-Gate-Size-Decimal": "1"
-}
-
-if __name__ == "__main__":
- ws = websocket.WebSocketApp(
- WS_URL,
- on_message=on_message,
- on_error=on_error,
- on_close=on_close,
- on_open=on_open,
- header=custom_headers
- )
- ws.run_forever()
-
-Copy
-{
- "time": 1680772890,
- "channel": "futures.order_place",
- "event": "api",
- "payload": {
- "req_id": "xxxx",
- "req_param": {
- "contract": "BTC_USDT",
- "size": "10",
- "price": "80048.240000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
- }
-}
-Copy
-#Websocket API 服务响应
-服务器响应包括对客户端请求的 ack 响应和 api 结果消息推送。 服务器响应遵循通用的 JSON 格式,其中包含以下字段:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»x_gate_ratelimit_requests_remain Integer (仅涉及下单/改单/撤单)当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit Integer (仅涉及下单/改单/撤单)当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp Integer (仅涉及下单/改单/撤单)已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-data Object 请求响应的数据
-»result Object 如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-服务器回声确认响应示例(目前仅在下单请求中有回声响应)
-
-{
- "request_id": "request-id-1",
- "ack": true,
- "header": {
- "response_time": "1681195121499",
- "status": "200",
- "channel": "futures.order_place",
- "event": "api",
- "client_id": "::1-0x140031563c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gate_ratelimit_reset_timestamp": 1681195121499
- },
- "data": {
- "result": {
- "req_id": "request-id-1",
- "req_param": {
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31503.280000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
- }
- }
-}
-Copy
-服务器 API 响应示例
-
-{
- "request_id": "request-id-1",
- "ack": false,
- "header": {
- "response_time": "1681195121639",
- "status": "200",
- "channel": "futures.order_place",
- "event": "api",
- "client_id": "::1-0x140031563c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gate_ratelimit_reset_timestamp": 1681195121639
- },
- "data": {
- "result": {
- "id": 74046511,
- "user": 6790020,
- "create_time": 1681195121.754,
- "finish_time": 1681195121.754,
- "finish_as": "filled",
- "status": "finished",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31503.3",
- "tif": "gtc",
- "fill_price": "31500",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0",
- "stp_id": 2,
- "stp_act": "cn",
- "amend_text": "-"
- }
- }
-}
-Copy
-#错误
-错误响应详情具有以下格式:
-
-
-名称 类型 描述
-label String 错误类型
-message String 详细错误信息
-限频相关的错误码说明:
-
-错误码 描述
-100 限流内部异常错误
-311 合约限流
-312 合约成交比率限流
-错误响应通知示例
-
-{
- "request_id": "request-id-1",
- "ack": false,
- "header": {
- "response_time": "1681195360034",
- "status": "401",
- "channel": "futures.login",
- "event": "api",
- "client_id": "::1-0x140001a2600",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d"
- },
- "data": {
- "errs": {
- "label": "INVALID_KEY",
- "message": "Invalid key provided"
- }
- }
-}
-Copy
-Error 推送示例(限速)
-
-{
- "request_id": "xxxx",
- "header": {
- "response_time": "1677816784084",
- "status": "429",
- "channel": "futures.order_place",
- "event": "api",
- "client_id": "::1-0x14002ba2300",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_limit": 100,
- "x_gate_ratelimit_reset_timestamp": 1677816785084
- },
- "data": {
- "errs": {
- "label": "TOO_MANY_REQUESTS",
- "message": "Request Rate limit Exceeded (311)"
- }
- }
-}
-Copy
-#登录
-注意:您使用的 GateAPIv4 密钥对必须具有合约账户对应的权限(例如:order-place 频道必须具有合约账户写入权限), 如果启用了密钥的白名单,则您的出站 IP 地址必须在密钥的 IP 白名单中.
-
-#登录请求
-客户端 API 请求
-
-payload参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,将由服务器发回,以帮助您识别服务器响应哪个请求,
-它与外部的id不同
-api_key string 是 Apiv4 key
-req_header object 是 Apiv4 自定义 header
-signature string 是 Apiv4 签名
-timestamp string 是 Unix 时间戳(以秒为单位)
-WebSocket api 操作认证使用与 Gate APIv4 API 相同的签名计算方法,即 HexEncode(HMAC_SHA512(secret,signature_string)),但有以下区别:
-
-签名字符串拼接方式:<event>\n<channel>\n<req_param>\n<timestamp>, 其中<event>、<channel>、<req_param>、<timestamp>是对应的请求信息
-login频道中的 req_param始终为空字符串
-身份验证信息在请求正文中的payload字段中发送。
-代码示例
-
-import hmac
-import hashlib
-import json
-import time
-import websocket
-import ssl
-
-def get_api_signature(secret, channel, request_param, ts):
- key = f"api\n{channel}\n{request_param}\n{ts}"
- hash_object = hmac.new(secret.encode(), key.encode(), hashlib.sha512)
- return hash_object.hexdigest()
-
-class ApiPayload:
- def __init__(self, api_key, signature, timestamp, req_id, request_param):
- self.api_key = api_key
- self.signature = signature
- self.timestamp = timestamp
- self.req_id = req_id
- self.request_param = request_param
-
-class ApiRequest:
- def __init__(self, ts, channel, event, payload):
- self.time = ts
- self.channel = channel
- self.event = event
- self.payload = payload
-
-def main():
- api_key = "YOUR_API_KEY"
- secret = "YOUR_API_SECRET"
- request_param = ""
- channel = "futures.login"
- ts = int(time.time())
- request_id = f"{int(time.time() * 1000)}-1"
-
- payload = ApiPayload(
- api_key=api_key,
- signature=get_api_signature(secret, channel, request_param, ts),
- timestamp=str(ts),
- req_id=request_id,
- request_param=request_param
- )
-
- req = ApiRequest(ts=ts, channel=channel, event="api", payload=payload)
-
- print(get_api_signature(secret, channel, request_param, ts))
-
- req_json = json.dumps(req, default=lambda o: o.__dict__)
- print(req_json)
-
- # Connect to WebSocket
- ws_url = "wss://fx-ws.gateio.ws/v4/ws/usdt" # Replace with your WebSocket URL
- websocket.enableTrace(False)
- ws = websocket.create_connection(ws_url, sslopt={"cert_reqs": ssl.CERT_NONE})
-
- # Function to receive messages
- def recv_messages():
- while True:
- try:
- message = ws.recv()
- print(f"recv: {message}")
- except Exception as e:
- print(f"Error receiving message: {e}")
- ws.close()
- break
-
- # Start receiving messages in a separate thread
- import threading
- receive_thread = threading.Thread(target=recv_messages)
- receive_thread.start()
-
- # Send the request
- ws.send(req_json)
-
- # Keep the main thread running
- receive_thread.join()
-
-if __name__ == "__main__":
- main()
-Copy
-请求示例
-
-{
- "time": 1681984544,
- "channel": "futures.login",
- "event": "api",
- "payload": {
- "api_key": "ea83fad2604399da16bf97e6eea772a6",
- "signature": "6fa3824c8141f2b2283108558ec50966d7caf749bf04a3b604652325b50b47d2343d569d848373d58e65c49d9622ba2e73dc25797abef11c9f20c07da741591e",
- "timestamp": "1681984544",
- "req_id": "request-1"
- }
-}
-Copy
-#登录响应
-响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-data Object 请求响应的数据
-»result Object 如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»»api_key String 登录成功的 apikey
-»»uid String 登录成功的用户 ID
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-登录响应示例
-
-{
- "request_id": "request-1",
- "header": {
- "response_time": "1681985856666",
- "status": "200",
- "channel": "futures.login",
- "event": "api",
- "clientId": "",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d"
- },
- "data": {
- "result": {
- "api_key": "ea83fad2604399da16bf97e6eea772a6",
- "uid": "110284739"
- }
- }
-}
-Copy
-#下单
-futures.order_place
-
-您可以通过此频道进行下单操作.
-
-本频道和以下的 APIV4 功能相同:
-
-POST /futures/{
- settle
-}/orders
-#下单请求
-payload参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param object 是 使用 api 下单参数; api 下单参数详细信息api(opens new window)
-req_header object 否 Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段 类型 必选 描述
-contract string 是 合约
-size int64 是 订单大小。指定正数进行出价,指定负数进行询问
-iceberg string 否 冰山订单的显示尺寸。0 表示非冰山。请注意,您需要支付隐藏尺寸的接受者费用
-price string 否 订单价格。0 表示市价订单,tif设置为ioc
-close bool 否 设置为true平仓,size设置为 0
-reduce_only bool 否 设置为true仅减少订单
-tif string 否 有效时间
-text string 否 用户定义的信息。如果不为空,则必须遵循以下规则:
-auto_size string 否 将侧面设置为关闭双模式位置。close_long闭合长边;而close_short短的。注意size还需要设置为 0
-stp_act string 否 自我交易预防行动。用户可以通过该字段设置自助交易防范策略
-market_order_slip_ratio string 否 该笔市价单的预设的最大滑点比率(不代表实际的滑点),0.03代表3%的最大滑点
-req_header 自定义 header 数据:
-
-字段 类型 必选 描述
-x-gate-exptime string 否 指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-#详细描述
-tif: 有效时间
-
-gtc:取消前有效
-ioc: ImmediateOrCancelled, 仅接受者
-poc:PendingOrCancelled,仅发布订单,始终享受挂单费用
-fok:FillOrKill,完全填充或不填充
-text: 订单自定义信息,用户可以用该字段设置自定义 ID,用户自定义字段必须满足以下条件:
-
-必须以 t- 开头
-不计算 t- ,长度不能超过 28 字节
-输入内容只能包含数字、字母、下划线(_)、中划线(-) 或者点(.)
-不填,默认 apiv4-ws,来自 ws
-web:来自网络
-api:来自 API
-app:来自手机
-auto_deleveraging:来自 ADL
-liquidation:来自清算
-insurance:来自保险
-stp_act:自我交易预防行动。用户可以通过该字段设置自助交易防范策略 用户加入后STP Group,他可以通过stp_act限制用户的自我交易防范策略。如果stp_act不通过则默认为cn策略。 当用户没有加入时STP group,传递参数时会返回错误stp_act。 如果用户下单时没有使用stp_act,stp_act将返回-
-
-cn:取消最新订单,取消新订单并保留旧订单
-co:取消最旧的订单,取消旧订单并保留新订单
-cb:取消两者,新旧订单都会被取消
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-api_order = {
- "contract": "BTC_USDT",
- "size": 10,
- "price": "31503.280000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send(json.dumps(
- {"time": int(time.time()),
- "channel": "futures.order_place",
- "event": "api",
- "payload": {
- "req_id": "1ewq-3123w-5",
- "req_param": api_order
- }}
-))
-
-print(ws.recv())
-Copy
-请求示例
-
-{
- "time": 1681195484,
- "channel": "futures.order_place",
- "event": "api",
- "payload": {
- "req_id": "request-id-1",
- "req_param": {
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31503.280000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
- }
-}
-Copy
-#订单请求回声消息
-订单确认回声通知示例
-
-{
- "request_id": "request-id-1",
- "ack": true,
- "header": {
- "response_time": "1681195484268",
- "status": "200",
- "channel": "futures.order_place",
- "event": "api",
- "client_id": "::1-0x140001a2600",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gat_ratelimit_reset_timestamp": 1736408263764
- },
- "data": {
- "result": {
- "req_id": "request-id-1",
- "req_header": null,
- "req_param": {
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31503.280000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
- }
- }
-}
-Copy
-#下单结果通知
-下单时返回订单信息 响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-ack Bool "ack"消息的返回表示 WebSocket 的确认消息(目前在下单接口中存在)。
-如果ack为 false(false 该字段不会出现在响应中),则说明该消息是响应消息,可以判断请求是否成功<br / >通过检查data.errs。
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain Integer 当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit Integer 当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp Integer 已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-data Object 请求响应的数据
-»result Object 如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-响应返回示例
-
-{
- "request_id": "request-id-1",
- "ack": false,
- "header": {
- "response_time": "1681195484360",
- "status": "200",
- "channel": "futures.order_place",
- "event": "api",
- "client_id": "::1-0x140001a2600",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gat_ratelimit_reset_timestamp": 1736408263764
- },
- "data": {
- "result": {
- "id": 74046514,
- "user": 6790020,
- "create_time": 1681195484.462,
- "finish_time": 1681195484.462,
- "finish_as": "filled",
- "status": "finished",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31503.3",
- "tif": "gtc",
- "fill_price": "31500",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0",
- "stp_id": 2,
- "stp_act": "cn",
- "amend_text": "-"
- }
- }
-}
-Copy
-#批量下单
-futures.order_batch_place
-
-您可以通过该频道批量下单
-
-本频道和以下的 APIV4 功能相同:
-
-POST /futures/{
- settle
-}/batch_orders
-#批量下单请求
-payload 参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param object 是 参考 api 批量下单的请求数组; api 批量下单详情api(opens new window)
-req_header object 否 Apiv4 自定义 header
-req_param API 订单模型的 JSON 字节数据可以参考单个下单,是多个单个下单数组,详情参考下单
-
-req_header 自定义 header 数据:
-
-字段 类型 必选 描述
-x-gate-exptime string 否 指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-api_order=[
- {
- "contract": "BTC_USDT",
- "size": 10,
- "price": "31403.180000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
- ]
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send(json.dumps({
- "time": int(time.time()),
- "channel": "futures.order_batch_place",
- "event": "api",
- "payload": {
- "header":{
- "x-gate-channel-id":"xxxx",
- },
- "req_id": "1ewq-3123w-5",
- "req_param": api_order
- }
-}))
-
-print(ws.recv())
-Copy
-请求示例
-
-{
- "time": 1681196536,
- "channel": "futures.order_batch_place",
- "event": "api",
- "payload": {
- "req_id": "request-id-6",
- "req_param": [
- {
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31403.180000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
- ]
- }
-}
-Copy
-#批量下单确认通知
-确认通知示例
-
-{
- "request_id": "request-id-6",
- "ack": true,
- "header": {
- "response_time": "1681196536283",
- "status": "200",
- "channel": "futures.order_batch_place",
- "event": "api",
- "client_id": "::1-0x14002cfa0c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gat_ratelimit_reset_timestamp": 1736408263764
- },
- "data": {
- "result": {
- "req_id": "request-id-6",
- "req_header": null,
- "req_param": [
- {
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31403.180000",
- "tif": "gtc",
- "text": "t-my-custom-id"
- }
- ]
- }
- }
-}
-Copy
-#批量下单结果通知
-批量下单订单信息返回
-
-响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-ack Bool "ack"消息的返回表示 WebSocket 的确认消息(目前在下单接口中存在)。
-如果ack为 false(false 该字段不会出现在响应中),则说明该消息是响应消息,可以判断请求是否成功<br / >通过检查data.errs。
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain Integer 当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit Integer 当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp Integer 已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data Object 请求响应的数据
-»result Object 如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-响应返回示例
-
-{
- "request_id": "request-id-6",
- "ack": false,
- "header": {
- "response_time": "1681196536532",
- "status": "200",
- "channel": "futures.order_batch_place",
- "event": "api",
- "client_id": "::1-0x14002cfa0c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gat_ratelimit_reset_timestamp": 1736408263764
- },
- "data": {
- "result": [
- {
- "succeeded": true,
- "id": 74046545,
- "user": 6790020,
- "create_time": 1681196536.592,
- "status": "open",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31403.2",
- "tif": "gtc",
- "left": "10",
- "fill_price": "0",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0"
- }
- ]
- }
-}
-Copy
-#订单取消
-futures.order_cancel
-
-您可以通过此频道取消订单
-
-本频道和以下的 APIV4 功能相同:
-
-DELETE /futures/{
- settle
-}/orders/{
- order_id
-}
-#订单取消请求
-payload 参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param object 是 API 取消订单,详情至api(opens new window)
-req_header object 否 Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段 类型 必选 描述
-order_id string 是 成功创建订单时返回的订单 ID 或者用户创建时指定的自定义 ID(即text 字段)。
-req_header 自定义 header 数据:
-
-字段 类型 必选 描述
-x-gate-exptime string 否 指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_cancel_order = {
- "order_id": "74046514"
- }
-ws.send(json.dumps({
- "time": int(time.time()),
- "channel": "futures.order_cancel",
- "event": "api",
- "payload": {
- "req_id": "1ewq-3123w-5",
- "req_param": api_cancel_order
- }
-}))
-
-print(ws.recv())
-Copy
-订单取消请求示例
-
-{
- "time": 1681195485,
- "channel": "futures.order_cancel",
- "event": "api",
- "payload": {
- "req_id": "request-id-5",
- "req_param": {
- "order_id": "74046514"
- }
- }
-}
-Copy
-#订单取消通知
-响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain Integer 当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit Integer 当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp Integer 已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data Object 请求响应的数据
-»result Object 订单取消参数,详情至api(opens new window)
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-订单取消返回示例
-
-{
- "request_id": "request-id-5",
- "header": {
- "response_time": "1681196536282",
- "status": "200",
- "channel": "futures.order_cancel",
- "event": "api",
- "client_id": "::1-0x14002cfa0c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gat_ratelimit_reset_timestamp": 1736408263764
- },
- "data": {
- "result": {
- "id": 74046543,
- "user": 6790020,
- "create_time": 1681196535.01,
- "finish_time": 1681196536.343,
- "finish_as": "cancelled",
- "status": "finished",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31303.2",
- "tif": "gtc",
- "left": "10",
- "fill_price": "0",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0",
- "stp_id": 2,
- "stp_act": "cn",
- "amend_text": "-"
- }
- }
-}
-Copy
-#取消所有 ID 列表内的订单
-您可以使用此频道futures.order_cancel_ids取消所有 ID 列表内的订单。
-
-可以指定多个不同的订单id。一次请求最多只能撤销 20 条记录
-
-以下是 API 的功能:
-
-POST /futures/{settle}/batch_cancel_orders
-#取消所有 ID 列表内的订单请求
-Payload 格式:
-
-字段 类型 必选 描述
-req_id string 是 服务器将发送回的请求 ID,用于帮助您识别服务器响应的是哪个请求,它与外部的 id 不同。
-req_param array 是 订单 ID 列表
-req_header object 否 apiv4 自定义 header
-req_header 自定义 header 数据:
-
-字段 类型 必选 描述
-x-gate-exptime string 否 指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-#!/usr/bin/python
-
-import time
-import json
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-cancelWithIdsParam = ["1694883366","123"]
-ws.send(json.dumps({
- "time":int(time.time()),
- "channel":"futures.order_cancel_ids",
- "event":"api",
- "payload":{
- "req_id":"test_1",
- "req_param": cancelWithIdsParam
- }
-}))
-
-print(ws.recv())
-Copy
-客户端请求示例
-
-{
- "time": 1681986208,
- "channel": "futures.order_cancel_ids",
- "event": "api",
- "payload": {
- "req_id": "request-9",
- "req_param": [
- "1700664343",
- "123"
- ]
- }
-}
-Copy
-#取消所有 ID 列表内的订单推送
-推送格式:
-
-字段 类型 描述
-request_id String 消息的唯一标识符
-header Map 响应的元信息
-»response_time String 响应发送时间(以毫秒为单位)
-»channel String 请求的频道
-»event String 请求事件
-»client_id String 唯一客户端标识 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-data Object 请求响应的数据
-»result Object 响应详见api(opens new window)
-»errs Object 只有在请求失败时才可用
-»»label String 以字符串格式表示错误类型
-»»message String 错误信息详情
-取消订单推送示例
-
-{
- "request_id": "request-9",
- "header": {
- "response_time": "1681986208564",
- "status": "200",
- "channel": "futures.order_cancel_ids",
- "event": "api",
- "client_id": "::1-0x140001623c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d"
- },
- "data": {
- "result": [
- {
- "id": "1694883366",
- "user_id": 111,
- "succeeded": true
- },
- {
- "id": "123",
- "user_id": 111,
- "message": "ORDER_NOT_FOUND"
- }
- ]
- }
-}
-Copy
-#取消匹配的未结束订单
-futures.order_cancel_cp
-
-您可以通过此渠道取消所有匹配的未结束的订单
-
-本频道和以下的 APIV4 功能相同:
-
-DELETE /futures/{
- settle
-}/orders
-#请求
-payload 参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param object 是 详情至api(opens new window)
-req_header object 否 Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段 类型 必选 描述
-contract string 是 合约
-side string 否 所有出价或要价。如果没有特别说明,两者都包括在内。
-req_header 自定义 header 数据:
-
-字段 类型 必选 描述
-x-gate-exptime string 否 指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_cancel_all_order = {
- "contract": "BTC_USDT",
- "side": "bid"
- }
-ws.send(json.dumps({
- "time": int(time.time()),
- "channel": "futures.order_cancel_cp",
- "event": "api",
- "payload": {
- "req_id": "1ewq-3123w-5",
- "req_param": api_cancel_all_order
- }
-}))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
- "time": 1681196537,
- "channel": "futures.order_cancel_cp",
- "event": "api",
- "payload": {
- "req_id": "request-id-7",
- "req_param": {
- "contract": "BTC_USDT",
- "side": "bid"
- }
- }
-}
-Copy
-#响应结果
-响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain Integer 当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit Integer 当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp Integer 已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data Object 请求响应的数据
-»result Object 详情至api(opens new window)
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-订单取消返回示例
-
-{
- "request_id": "request-id-7",
- "header": {
- "response_time": "1681196537567",
- "status": "200",
- "channel": "futures.order_cancel_cp",
- "event": "api",
- "client_id": "::1-0x14002cfa0c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gat_ratelimit_reset_timestamp": 1736408263764
- },
- "data": {
- "result": [
- {
- "id": 74046545,
- "user": 6790020,
- "create_time": 1681196536.592,
- "finish_time": 1681196537.626,
- "finish_as": "cancelled",
- "status": "finished",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31403.2",
- "tif": "gtc",
- "left": "10",
- "fill_price": "0",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0",
- "stp_id": 2,
- "stp_act": "cn",
- "amend_text": "-"
- }
- ]
- }
-}
-Copy
-#修改订单
-futures.order_amend
-
-您可以通过此频道修改未结束的订单
-
-本频道和以下的 APIV4 功能相同:
-
-PUT /futures/{settle}/orders/{order_id}
-#请求
-payload 参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param object 是 API 修改订单参数,详情至api(opens new window)
-req_header object 否 Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段 类型 必选 描述
-order_id string 是 成功创建订单时返回的订单 ID 或者用户创建时指定的自定义 ID(即text 字段)。
-size int64 否 必选。交易数量,正数为买入,负数为卖出。平仓委托则设置为 0。
-price string 否 价格
-amend_text int64 否 修改订单时的自定义信息
-req_header 自定义 header 数据:
-
-字段 类型 必选 描述
-x-gate-exptime string 否 指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-#详细描述
-=> size: 新订单尺寸,包括已填充部分。
-
-如果新尺寸小于或等于已填充尺寸,订单将被取消。
-订单面必须与原始面相同。
-平仓订单大小无法更改。
-对于仅减少订单,增加尺寸可能会导致其他仅减少订单被取消。
-如果价格不变,减少数量不会改变其在订单簿中的优先级,而增加数量则会以当前价格将其移至最后。
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_amend_order = {
- "order_id": "74046543",
- "price": "31303.180000"
- }
-ws.send(json.dumps({
- "time": int(time.time()),
- "channel": "futures.order_amend",
- "event": "api",
- "payload": {
- "req_id": "1ewq-3123w-5",
- "req_param": api_amend_order
- }
-}))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
- "time": 1681196536,
- "channel": "futures.order_amend",
- "event": "api",
- "payload": {
- "req_id": "request-id-4",
- "req_param": {
- "order_id": "74046543",
- "price": "31303.180000"
- }
- }
-}
-Copy
-#响应结果
-响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain Integer 当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit Integer 当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp Integer 已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data Object 请求响应的数据
-»result Object 详情至api(opens new window)
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-订单修改返回示例
-
-{
- "request_id": "request-id-4",
- "header": {
- "response_time": "1681196536251",
- "status": "200",
- "channel": "futures.order_amend",
- "event": "api",
- "client_id": "::1-0x14002cfa0c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d",
- "x_gate_ratelimit_requests_remain": 99,
- "x_gate_ratelimit_limit": 100,
- "x_gat_ratelimit_reset_timestamp": 1736408263764
- },
- "data": {
- "result": {
- "id": 74046543,
- "user": 6790020,
- "create_time": 1681196535.01,
- "status": "open",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31303.2",
- "tif": "gtc",
- "left": "10",
- "fill_price": "0",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0",
- "stp_id": 2,
- "stp_act": "cn",
- "amend_text": "-"
- }
- }
-}
-Copy
-#获取订单列表
-futures.order_list
-
-您可以通过此频道获取订单列表
-
-本频道和以下的 APIV4 功能相同:
-
-GET /futures/{settle}/orders
-#订单列表请求
-payload 参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param object 是 API 请求订单列表参数,详情至api(opens new window)
-req_param API 订单模型的 JSON 字节数据:
-
-字段 类型 必选 描述
-contract string 否 合约标识,如果指定则只返回该合约相关数据
-status string 是 只列出具有此状态的订单
-limit int 否 单个列表中返回的最大记录数
-offset int 否 列表偏移量,从 0 开始
-last_id string 否 使用先前列表查询结果中最后一条记录的id 指定列表起始点
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_list_order = {
- "contract": "BTC_USDT",
- "status": "open"
- }
-ws.send(json.dumps({
- "time": int(time.time()),
- "channel": "futures.order_list",
- "event": "api",
- "payload": {
- "req_id": "1ewq-3123w-5",
- "req_param": api_list_order
- }
-}
-))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
- "time": 1681196535,
- "channel": "futures.order_list",
- "event": "api",
- "payload": {
- "req_id": "request-id-3",
- "req_param": {
- "contract": "BTC_USDT",
- "status": "open"
- }
- }
-}
-Copy
-#订单列表响应
-响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-data Object 请求响应的数据
-»result Object 详情至api(opens new window)
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-订单列表返回示例
-
-{
- "request_id": "request-id-3",
- "header": {
- "response_time": "1681196536017",
- "status": "200",
- "channel": "futures.order_list",
- "event": "api",
- "client_id": "::1-0x14002cfa0c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d"
- },
- "data": {
- "result": [
- {
- "id": 74046543,
- "user": 6790020,
- "create_time": 1681196535.01,
- "finish_time": 1681196535.01,
- "update_time": 1681196535.01,
- "finish_as": "filled",
- "status": "open",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31403.2",
- "tif": "gtc",
- "left": "10",
- "fill_price": "0",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0",
- "stp_id": 2,
- "stp_act": "cn",
- "amend_text": "-"
- }
- ]
- }
-}
-Copy
-#查询订单详情
-futures.order_status
-
-您可以通过该频道查询订单详情
-
-本频道和以下的 APIV4 功能相同:
-
-GET /futures/{settle}/orders/{order_id}
-#订单详情请求
-payload 参数:
-
-名称 类型 必选 描述
-req_id string 是 请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param object 是 详情至api(opens new window)
-req_param` API 订单模型的 JSON 字节数据:
-
-字段 类型 必选 描述
-order_id string 是 成功创建订单时返回的订单 ID 或者用户创建时指定的自定义 ID(即text 字段)。
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-
-api_status_order = {
- "order_id": "74046543"
- }
-
-ws.send(json.dumps({
- "time": int(time.time()),
- "channel": "futures.order_status",
- "event": "api",
- "payload": {
- "req_id": "1ewq-3123w-5",
- "req_param": api_status_order
- }
-}))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
- "time": 1681196535,
- "channel": "futures.order_status",
- "event": "api",
- "payload": {
- "req_id": "request-id-2",
- "req_param": {
- "order_id": "74046543"
- }
- }
-}
-Copy
-#订单详情响应
-响应参数:
-
-名称 类型 描述
-request_id String 对应的请求 ID
-header Map 响应元信息
-»response_time String 响应发送时间(毫秒)
-»channel String 请求频道
-»event String 请求event
-»client_id String 唯一的客户端 ID
-»x_in_time Integer ws 接收请求的时间(以微秒为单位)
-»x_out_time Integer ws 返回响应的时间(以微秒为单位)
-»conn_id String 与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id String 与客户端建立连接的TraceId
-»trace_id String 执行下单操作的TraceId
-data Object 请求响应的数据
-»result Object 详情至api(opens new window)
-»errs Object 仅当请求失败时可用
-»»label String 错误类型
-»»message String 详细错误信息
-订单详情返回示例
-
-{
- "request_id": "request-id-2",
- "header": {
- "response_time": "1681196535985",
- "status": "200",
- "channel": "futures.order_status",
- "event": "api",
- "client_id": "::1-0x14002cfa0c0",
- "x_in_time": 1681985856667508,
- "x_out_time": 1681985856667598,
- "conn_id": "5e74253e9c793974",
- "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
- "trace_id": "e410abb5f74b4afc519e67920548838d"
- },
- "data": {
- "result": {
- "id": 74046543,
- "user": 6790020,
- "create_time": 1681196535.01,
- "status": "open",
- "contract": "BTC_USDT",
- "size": "10",
- "price": "31403.2",
- "tif": "gtc",
- "left": "10",
- "fill_price": "0",
- "text": "t-my-custom-id",
- "tkfr": "0.0003",
- "mkfr": "0",
- "stp_id": 2,
- "stp_act": "cn",
- "amend_text": "-"
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md b/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
deleted file mode 100644
index 42a2dc6..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
+++ /dev/null
@@ -1,583 +0,0 @@
-# Gate Api 模块 — 网格交易系统
-
-## 文件列表
-
-| 文件 | 类型 | 说明 |
-|------|------|------|
-| [GateWebSocketClientManager](#gatewebsocketclientmanager) | `@Component` | Spring 启动入口,组装组件 + 生命周期 |
-| [GateConfig](#gateconfig) | 配置 | Builder 模式:API 密钥、合约、策略参数、环境切换 |
-| [GateKlineWebSocketClient](#gateklinewebsocketclient) | WS 连接管理 | 连接/心跳/重连/消息路由 |
-| [GateGridTradeService](#gategridtradeservice) | 策略核心 | 网格队列 + 条件开仓单 + 订单订阅止盈 + 反向条件单 |
-| [GateTradeExecutor](#gatetradeexecutor) | 异步执行器 | 独立线程池执行 REST 下单,成功/失败双回调 |
-
-### wsHandler 子包
-
-| 文件 | 类型 | 说明 |
-|------|------|------|
-| `wsHandler/GateChannelHandler.java` | **接口** | subscribe / unsubscribe / handleMessage / getChannelName |
-| `wsHandler/AbstractPrivateChannelHandler.java` | **抽象类** | 私有频道基类:HMAC-SHA512 签名 + 认证请求 |
-| `wsHandler/handler/CandlestickChannelHandler.java` | 公开频道 | K 线解析 → `onKline()` |
-| `wsHandler/handler/PositionsChannelHandler.java` | 私有频道 | 仓位推送 → `onPositionUpdate()`,日志输出全部 20 个推送字段 |
-| `wsHandler/handler/PositionClosesChannelHandler.java` | 私有频道 | 平仓推送 → `onPositionClose()` |
-| `wsHandler/handler/OrdersChannelHandler.java` | 私有频道 | 订单推送 → `onOrderUpdate()`(订单订阅止盈匹配) |
-
----
-
-## 架构总览
-
-```
-┌──────────────────────────────────────────────────────────────────┐
-│ GateWebSocketClientManager │
-│ (Spring @Component) │
-│ │
-│ GateConfig.builder() → GateGridTradeService + WS Client │
-│ │ │ │ │
-│ │ REST BasePath │ GateTradeExecutor │ WS URL │
-│ ▼ ▼ ▼ │
-│ Gate API (REST) 独立线程池 (async) Gate WebSocket │
-│ onSuccess/onFailure双回调 ┌──────────────┐ │
-│ │Candlestick H │ │
-│ │Positions H │ │
-│ │PosCloses H │ │
-│ │Orders H │ │
-│ └──────────────┘ │
-└──────────────────────────────────────────────────────────────────┘
-```
-
----
-
-## WebSocket 频道
-
-| 频道 | 类型 | 作用 |
-|------|------|------|
-| `futures.candlesticks` | 公开 | K 线推送 → `onKline()` 驱动网格触发 |
-| `futures.positions` | 私有 | 仓位推送 → `onPositionUpdate()` 记录入场价/持仓量、处理反向单 |
-| `futures.position_closes` | 私有 | 平仓推送 → `onPositionClose()` 累加已实现盈亏 |
-| `futures.orders` | 私有 | 订单推送 → `onOrderUpdate()` 订阅条件单成交,匹配止盈价 |
-
----
-
-## 数据流
-
-```
-WebSocket → GateKlineWebSocketClient.handleMessage → 路由 dispatch
-│
-├─ futures.pong → cancelPongTimeout
-├─ subscribe / unsubscribe / error → log
-│
-├─ futures.candlesticks (公开)
-│ └─ CandlestickChannelHandler
-│ └─ gridTradeService.onKline(closePrice, timestamp)
-│ ├─ 更新 unrealizedPnl(浮动盈亏)
-│ ├─ state=WAITING_KLINE → 异步双开基底仓位
-│ └─ state=ACTIVE → 方向区分: closePrice>longPriceQueue[0]→processLongGrid,
-│ closePrice<shortPriceQueue[0]→processShortGrid, 其余跳过(一个K线只触发一个方向)
-│
-├─ futures.positions (私有, HMAC-SHA512)
-│ └─ PositionsChannelHandler
-│ ├─ 解析 mode → Position.ModeEnum(DUAL_LONG / DUAL_SHORT)
-│ ├─ 日志输出全部 20 个推送字段
-│ └─ gridTradeService.onPositionUpdate(contract, mode, size, entryPrice)
-│ ├─ 有仓位: 基底首次成交记录入场价 → tryGenerateQueues
-│ ├─ 仓位净减少(size < positionSize)→ 检查反向条件单条件 →
-│ │ 满足则开反向市价单(止盈价 = entryPrice ± step),orderId+止盈价存入 Map
-│ ├─ 仓位不变或增加 → 仅更新 positionSize
-│ └─ 无仓位(size=0): 清空活跃标记和持仓量
-│
-├─ futures.position_closes (私有, HMAC-SHA512)
-│ └─ PositionClosesChannelHandler
-│ └─ gridTradeService.onPositionClose(contract, side, pnl)
-│ └─ cumulativePnl += pnl → checkStopConditions()
-│
-├─ futures.orders (私有, HMAC-SHA512) ← 订单订阅止盈核心
-│ └─ OrdersChannelHandler
-│ └─ gridTradeService.onOrderUpdate(orderId, status, finishAs)
-│ └─ 条件单成交(status=finished, finish_as=filled)→
-│ 从 Map 中 remove(orderId) 取出止盈价 →
-│ executor.placeTakeProfit(止盈价, ...)
-│
-└─ 所有下单操作
- └─ GateTradeExecutor (单线程 + 64队列 + CallerRunsPolicy)
- ├─ openLong/openShort → 市价 IOC 开仓(基底双开 + 反向开仓)
- ├─ placeConditionalEntryOrder → 条件开仓单(网格触发,服务端监控价格触发后市价 IOC)
- ├─ cancelConditionalOrder → 取消指定条件单
- ├─ placeTakeProfit → 止盈条件单(plan-close-*-position)
- ├─ cancelAllPriceTriggeredOrders → 清除所有条件单(停止时)
- ├─ placeGridLimitOrder → 【遗留】限价 GTC 单(当前策略未使用)
- └─ cancelOrder → 【遗留】取消限价单(当前策略未使用)
-```
-
----
-
-## 策略状态机
-
-```
-WAITING_KLINE ──onKline──→ OPENING ──双基底都成交──→ ACTIVE
- │ │ │
- │ 下单异常 ├─ 每根K线: 更新 unrealizedPnl
- │ │ ├─ cumPnl ≥ overallTp → STOPPED
- │ │ ├─ cumPnl ≤ -maxLoss → STOPPED
- │ │ ├─ 保证金超限 → 跳过挂单,队列照常更新
- │ │ ├─ 方向区分 → processShortGrid 或 processLongGrid(二者选一)
- │ │ ├─ 网格触发 → 匹配队列→本队补充→挂新条件单
- │ │ │ (止盈价随 orderId 存入 Map)
- │ │ ├─ 订单推送(futures.orders) → 订阅匹配止盈价 →
- │ │ │ 挂止盈条件单(plan-close-*-position)
- │ │ └─ 仓位推送(净减少) → 反向市价单
- ▼ ▼
- STOPPED ←──────────────────┘
-```
-
-| 状态 | 含义 |
-|------|------|
-| `WAITING_KLINE` | 等待首次K线价格 |
-| `OPENING` | 正在异步开基底多空仓位(已提交到GateTradeExecutor) |
-| `ACTIVE` | 网格队列激活,K线触发网格 → 挂条件单 → 订单订阅匹配止盈 |
-| `STOPPED` | 停止(盈利达标 / 亏损超限) |
-
----
-
-## 策略核心:网格队列 + 条件单 + 订单订阅止盈
-
-### 概述
-
-策略采用"基底 + 价格网格队列"模式:先开一对基底多空仓位,然后以基底入场价为基准生成价格队列。每当 K 线穿破队列元素,匹配后更新队列并挂新条件单。条件单成交后通过 `futures.orders` 推送匹配止盈价并挂止盈条件单。
-
-### 核心数据结构
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| shortPriceQueue | `List<BigDecimal>` 同步列表 | 空仓价格队列,降序(大→小),容量 gridQueueSize |
-| longPriceQueue | `List<BigDecimal>` 同步列表 | 多仓价格队列,升序(小→大),容量 gridQueueSize |
-| currentLongOrderIds | `Map<String, BigDecimal>` 同步 LinkedHashMap | **多仓条件单映射**:orderId → 止盈价,超 5 个时截断保留最新 |
-| currentShortOrderIds | `Map<String, BigDecimal>` 同步 LinkedHashMap | **空仓条件单映射**:orderId → 止盈价,超 5 个时截断保留最新 |
-| shortBaseEntryPrice | `BigDecimal` | 基底空头入场价(仅记录,用于队列生成基准) |
-| longBaseEntryPrice | `BigDecimal` | 基底多头入场价(仅记录,当前未被业务逻辑消费) |
-| shortEntryPrice | `BigDecimal` | 当前空仓加权均价(推送实时更新) |
-| longEntryPrice | `BigDecimal` | 当前多仓加权均价(推送实时更新) |
-| shortPositionSize | `BigDecimal` | 当前空仓持仓量(绝对值) |
-| longPositionSize | `BigDecimal` | 当前多仓持仓量 |
-| cumulativePnl | `BigDecimal` | 累计已实现盈亏(平仓推送驱动) |
-| unrealizedPnl | `BigDecimal` | 未实现盈亏(每根K线更新) |
-| initialPrincipal | `BigDecimal` | 初始本金(启动时账户总资产) |
-
-### 条件单设计
-
-**为什么用条件单而不是限价单?**
-
-限价单 `price=X, tif=GTC` 在价格位于挂单价有利侧时**会立即成交**。改用 Gate API `FuturesPriceTriggeredOrder`(价格触发条件单),由服务端监控价格,**只有当前价格抵达触发价时才执行**,避免提前成交。
-
-**条件单结构**:
-```
-FuturesPriceTriggeredOrder
- ├─ trigger: { price=触发价, rule=NUMBER_1(≥) 或 NUMBER_2(≤), expiration=0(永久有效) }
- ├─ initial: { contract, size(正=开多/负=开空), price="0", tif=IOC, reduce_only=false }
- └─ order_type: strategy_type=NUMBER_0(价格触发), price_type=NUMBER_0(最新价)
-```
-
-### 订单订阅止盈机制(核心)
-
-**这是当前版本的止盈流程,替代了旧版的止盈队列消费模式。**
-
-```
-挂条件开仓单时 → onSuccess 回调 → currentXxxOrderIds.put(orderId, 止盈价)
- ↓
-条件单成交 → futures.orders 推送 → onOrderUpdate(orderId, "finished", "filled")
- ↓
- currentXxxOrderIds.remove(orderId) 取出止盈价
- ↓
- executor.placeTakeProfit(止盈价, 方向参数)
-```
-
-止盈价计算:
-- **网格触发**(`processShortGrid`/`processLongGrid`):`newFirst ± step`
-- **初始条件单**(`tryGenerateQueues`):`queue[0] ± step`
-- **反向市价单**(`onPositionUpdate`):`entryPrice ± step`
-
-### Map 截断机制
-
-`currentLongOrderIds` / `currentShortOrderIds` 为 `LinkedHashMap`(保持插入顺序)。在 `onPositionUpdate` 中,当 Map size > 5 时,从头部(最旧条目)开始删除,只保留最新 5 条。防止条件单挂单失败导致 Map 无限膨胀。
-
-### 基底开仓
-
-```
-K线到达 → 双开基底(市价开多 + 市价开空,IOC)
- → 成交回调: baseLongOpened=true, longActive=true
- → 成交回调: baseShortOpened=true, shortActive=true
- → 两者都成交 → generateShortQueue() + generateLongQueue()
- + 挂初始条件开仓单 → state=ACTIVE
-```
-
-### 初始条件开仓单
-
-队列生成后立即用队列首元素挂两个价格触发条件单:
-
-| 方向 | 触发价 | rule | size | 止盈价(存入Map) |
-|------|--------|------|------|-------------------|
-| 多仓条件单 | longPriceQueue[0] | NUMBER_1 (≥触发价) | +quantity | 触发价 + step |
-| 空仓条件单 | shortPriceQueue[0] | NUMBER_2 (≤触发价) | -quantity | 触发价 − step |
-
-### 网格队列生成
-
-以空头基底入场价 `shortBaseEntryPrice` 为唯一基准,计算绝对步长 `step = shortBaseEntryPrice × gridRate`(保留1位小数)。
-
-两个队列均从 `shortBaseEntryPrice` 出发,按 `step` 绝对偏移生成 N 个价格(N = gridQueueSize,默认 50):
-
-| 队列 | 计算方式 | 排序 |
-|------|---------|------|
-| 空仓队列 shortPriceQueue | 首元素 = shortBaseEntryPrice − step,后续依次 −step | 降序(大→小) |
-| 多仓队列 longPriceQueue | 首元素 = shortBaseEntryPrice + step,后续依次 +step | 升序(小→大) |
-
----
-
-## K线触发网格
-
-```
-K线到达(ACTIVE状态):
-│
-├─ closePrice > longPriceQueue[0] → processLongGrid(价格涨超队列首)
-│ ├─ 匹配: 收集所有 < closePrice 的多仓队列元素(升序,一旦遇≥即停止)
-│ ├─ 多仓队列: 移除 matched,尾部补充(尾价 + step 循环递增)
-│ ├─ 空仓队列: 不再更新(队列转移逻辑已移除)
-│ ├─ 保证金检查:
-│ │ ├─ 安全 → 挂新多仓条件单(触发价=新 long[0], 止盈=新 long[0]+step, orderId→Map)
-│ │ │ → 空仓守卫: newShortFirst = newLongFirst − step×2,
-│ │ │ 若 > shortEntryPrice → 挂新空仓条件单(止盈=新short[0]−step, orderId→Map)
-│ │ └─ 超限 → 跳过挂单(队列照常更新)
-│ └─ 条件单成交后由 futures.orders 推送 → onOrderUpdate 匹配止盈价 → 挂止盈条件单
-│
-└─ closePrice < shortPriceQueue[0] → processShortGrid(价格跌穿队列首)
- ├─ 匹配: 收集所有 > closePrice 的空仓队列元素(降序,一旦遇≤即停止)
- ├─ 空仓队列: 移除 matched,尾部补充(尾价 − step 循环递减)
- ├─ 多仓队列: 不再更新(队列转移逻辑已移除)
- ├─ 保证金检查:
- │ ├─ 安全 → 挂新空仓条件单(触发价=新 short[0], 止盈=新short[0]−step, orderId→Map)
- │ │ → 多仓守卫: newLongFirst = newShortFirst + step×2,
- │ │ 若 < longEntryPrice → 挂新多仓条件单(止盈=新long[0]+step, orderId→Map)
- │ └─ 超限 → 跳过挂单(队列照常更新)
- └─ 条件单成交后由 futures.orders 推送 → onOrderUpdate 匹配止盈价 → 挂止盈条件单
-
-closePrice 既不 > longPriceQueue[0] 也不 < shortPriceQueue[0] → 跳过本次K线
-```
-
-> **关键变更**:不再有"队列转移"(对方队列不再更新)、不再有"取消旧条件单"(旧单由 Map 自动覆盖或服务端自动取消)、不再有"止盈队列"(改为订单订阅匹配)。
-> 反向条件单不再在 process*Grid 中处理,改为在 onPositionUpdate 仓位净减少时触发。
-
-### 队列更新示意
-
-```
-ETH_USDT, gridRate=0.0035, shortBaseEntryPrice=2270, step=2270×0.0035≈7.9, gridQueueSize=4:
-
-初始状态:
- 空仓队列: [2262.1, 2254.2, 2246.3, 2238.4] (降序)
- 多仓队列: [2277.9, 2285.8, 2293.7, 2301.6] (升序)
- 初始条件单: 多仓触发价=2277.9(止盈=2285.8→currentLongOrderIds),
- 空仓触发价=2262.1(止盈=2254.2→currentShortOrderIds)
-
-价格涨到 2290 → processLongGrid 触发:
- 匹配: [2277.9, 2285.8](都 < 2290)
-
- 多仓队列: 移除[2277.9,2285.8] → [2293.7,2301.6]
- 补充: 2301.6+7.9=2309.5 → 2309.5+7.9=2317.4
- → [2293.7, 2301.6, 2309.5, 2317.4]
-
- 空仓队列: 不变(队列转移已移除)→ [2262.1, 2254.2, 2246.3, 2238.4]
-
- 挂新多仓条件单(触发价=2293.7, 止盈=2301.6→currentLongOrderIds)
- 空仓守卫: newShortFirst=2293.7−15.8=2277.9 > 2262.1? → 满足,
- 挂新空仓条件单(触发价=2277.9, 止盈=2270.0→currentShortOrderIds)
-
-条件单 2293.7 成交 → futures.orders 推送:
- → onOrderUpdate(orderId, "finished", "filled")
- → currentLongOrderIds.remove(orderId) = 2301.6
- → placeTakeProfit(2301.6, NUMBER_1, plan-close-long-position, -1)
-```
-
----
-
-## 仓位更新逻辑(onPositionUpdate)
-
-```
-仓位推送:
-├─ size ≠ 0:
-│ ├─ 基底首次成交 → 记录 baseEntryPrice → tryGenerateQueues
-│ ├─ 仓位净减少(size.abs() < positionSize):
-│ │ ├─ DUAL_LONG 仓位减少且有反向条件单(newShortFirst > shortEntryPrice
-│ │ │ 且 < longEntryPrice 且 shortPositionSize < 3):
-│ │ │ → 市价开空(止盈=longEntryPrice−step→currentShortOrderIds)
-│ │ │ → 累加 positionSize 标记(最多3次)
-│ │ └─ DUAL_SHORT 仓位减少且有反向条件单(newLongFirst > shortEntryPrice
-│ │ 且 < longEntryPrice 且 longPositionSize < 3):
-│ │ → 市价开多(止盈=shortEntryPrice+step→currentLongOrderIds)
-│ │ → 累加 positionSize 标记(最多3次)
-│ └─ 仓位不变或增加 → 仅更新 positionSize
-└─ size = 0:
- └─ 清空活跃标记,重置持仓量为0
-
-每次更新后: 截断 currentLongOrderIds / currentShortOrderIds 到最多 5 个元素
-```
-
----
-
-## 策略时序
-
-### 阶段 1:启动与初始化
-
-```
-Spring @PostConstruct
- → GateConfig.builder()...build()
- → GateGridTradeService(config)
- → init():
- 1. 查用户ID(用于私有频道订阅)
- 2. 查账户 → 记录初始本金 initialPrincipal → 如需要切持仓模式
- 3. 清除旧止盈止损条件单
- 4. 查当前合约所有仓位 → 逐个市价平仓(reduce_only, IOC)
- - 单向持仓: size=相反数平仓
- - 双向持仓: size=0, close=false, autoSize=LONG/SHORT
- 5. 设杠杆
- → GateKlineWebSocketClient(config.getWsUrl())
- → addChannelHandler x4 → init() → connect()
- → onOpen: handlers依次subscribe → sendPing
- → gridTradeService.startGrid() → state=WAITING_KLINE
-```
-
-### 阶段 2:基底开仓 → 生成网格队列 → 挂条件单
-
-```
-K线推送 → onKline(closePrice) → state=OPENING
- → executor.openLong(qty, onSuccess, onFailure)
- → 成交 → 仓位推送: DUAL_LONG, size>0, entryPrice=X
- → baseLongOpened=true, longBaseEntryPrice=X
- → tryGenerateQueues(): 双基底都成交? → 生成队列+挂初始条件单 → state=ACTIVE
- → executor.openShort(-qty, onSuccess, onFailure)
- → 成交 → 仓位推送: DUAL_SHORT, size<0, entryPrice=Y
- → baseShortOpened=true, shortBaseEntryPrice=Y
- → tryGenerateQueues(): 双基底都成交? → 生成队列+挂初始条件单 → state=ACTIVE
-```
-
-### 阶段 3:ACTIVE 状态 — K线驱动网格 + 订单订阅止盈
-
-```
-每根K线 → onKline → updateUnrealizedPnl → 方向区分(一个K线只触发一个方向)
-
-processShortGrid / processLongGrid:
- → 匹配 → 本队补充 → 保证金检查
- → 挂新条件单(止盈价随 orderId 存入 Map)
- → 对方守卫:满足条件时挂对方方向新条件单
-
-条件单被触发成交后 → futures.orders 推送:
- → onOrderUpdate(orderId, "finished", "filled")
- → Map.remove(orderId) 取出止盈价
- → executor.placeTakeProfit(止盈价, 方向参数, plan-close-*-position)
-
-仓位净减少时 → onPositionUpdate:
- → 满足反向条件 → 开反向市价单(止盈价 = entryPrice ± step,orderId+止盈价存入 Map)
-```
-
-### 阶段 4:停止
-
-```
-平仓推送: pnl=+0.6 → cumulativePnl=0.6 ≥ overallTp(0.5) → state=STOPPED
-平仓推送: pnl=-8.0 → cumulativePnl=-8.0 ≤ -maxLoss(7.5) → state=STOPPED
-```
-
----
-
-## GateConfig
-
-**角色**: 统一配置中心。Builder模式管理所有参数,提供 REST/WS URL 环境自动切换。
-
-**核心方法**:
-- `getRestBasePath()`: isProduction ? 生产网 : 测试网
-- `getWsUrl()`: 同上
-
-**配置项**(含默认值):
-
-| 参数 | 默认值 | 说明 |
-|------|--------|------|
-| contract | BTC_USDT | 合约 |
-| leverage | 10 | 倍数 |
-| marginMode | cross | 全仓 |
-| positionMode | dual | 双向持仓 |
-| gridRate | 0.0035 | 网格间距比率 0.35% |
-| step | 运行时计算 | 网格绝对步长 = shortBaseEntryPrice × gridRate(保留1位小数) |
-| overallTp | 0.5 USDT | 整体止盈 |
-| maxLoss | 7.5 USDT | 最大亏损 |
-| quantity | 1 | 下单张数 |
-| gridQueueSize | 50 | 网格价格队列容量 |
-| marginRatioLimit | 0.2 | 保证金占初始本金比例上限(20%),超限跳过开仓 |
-| contractMultiplier | 0.001 | 合约乘数(单张合约代表的基础资产数量) |
-| unrealizedPnlPriceMode | LAST_PRICE | 未实现盈亏计价模式:LAST_PRICE / MARK_PRICE |
-
----
-
-## GateTradeExecutor
-
-**角色**: 独立线程池执行 REST API 下单。采用成功/失败双回调模式。
-
-**线程模型**:
-- `ThreadPoolExecutor(1, 1, 60s, LinkedBlockingQueue(64), CallerRunsPolicy)`
-- 单线程保序 + 有界队列防堆积 + CallerRuns背压
-- allowCoreThreadTimeOut: 60s 空闲后线程回收
-
-**回调设计**:
-- `openLong`/`openShort`/`placeTakeProfit`/`placeConditionalEntryOrder` 接受 `onSuccess` 和 `onFailure` 两个 `Consumer<String>`
-- REST 调用成功 → 执行 `onSuccess`(标记基底已开、记录 orderId+止盈价到 Map 等)
-- REST 调用失败 → 执行 `onFailure`(当前版本多为 null,依赖 position 推送修正)
-
-### 核心方法
-
-| 方法 | 说明 |
-|------|------|
-| `openLong(qty, onSuccess, onFailure)` | 异步 IOC 市价开多,双回调 |
-| `openShort(qty, onSuccess, onFailure)` | 异步 IOC 市价开空,双回调 |
-| `placeConditionalEntryOrder(triggerPrice, rule, size, onSuccess, onFailure)` | 异步**条件开仓单**。triggerPrice=监控价,rule 决定触发方向,size 正=开多/负=开空。触发后 price="0" + IOC 市价成交 |
-| `cancelConditionalOrder(orderId)` | 异步取消指定条件单(orderId 为 null 时跳过) |
-| `placeTakeProfit(trigger, rule, orderType, size)` | 异步**止盈条件单**(plan-close-*-position)。triggerPrice=止盈触发价,触发后 price="0" + IOC 市价平仓,reduce_only=true |
-| `cancelAllPriceTriggeredOrders()` | 清除所有条件单 |
-| `shutdown()` | 等待10秒,超时强制关闭 |
-
-### 遗留方法(当前策略未使用)
-
-| 方法 | 说明 |
-|------|------|
-| `placeGridLimitOrder(price, size, onSuccess, onFailure)` | 旧版限价 GTC 单,已被条件单替代 |
-| `cancelOrder(orderId)` | 旧版取消限价单,已被 cancelConditionalOrder 替代 |
-
-### 条件单 order_type 说明
-
-| order_type | 用途 | size 语义 |
-|-----------|------|----------|
-| `plan-close-long-position` | 部分/全部平多仓 | size<0 表示平多仓张数 |
-| `plan-close-short-position` | 部分/全部平空仓 | size>0 表示平空仓张数 |
-
-> **为何不用 close-*-position**:`close-long-position` 和 `close-short-position` 仅支持全部平仓(size=0),且双仓模式还需设置 `auto_size`。网格策略需要指定张数部分平仓,因此必须使用 `plan-close-*-position`。
-
-### 条件单构建 (buildTriggeredOrder)
-
-`FuturesPriceTriggeredOrder` 结构:
-
-| 组件 | 字段 | 开仓单值 | 止盈单值 |
-|------|------|---------|---------|
-| trigger | price | 触发价 | 止盈价 |
-| trigger | rule | NUMBER_1(≥) 或 NUMBER_2(≤) | 同左 |
-| trigger | strategy_type | 0 (价格触发) | 0 (价格触发) |
-| trigger | price_type | 0 (最新价) | 0 (最新价) |
-| trigger | expiration | 0 (永久有效) | 0 (永久有效) |
-| initial | contract | 合约名 | 合约名 |
-| initial | size | +qty(开多)/-qty(开空) | -qty(平多)/+qty(平空) |
-| initial | price | "0" (市价) | "0" (市价) |
-| initial | tif | IOC | IOC |
-| initial | reduce_only | false | true |
-| order_type | — | 不设置 | plan-close-long-position 或 plan-close-short-position |
-
----
-
-## GateGridTradeService
-
-**角色**: 策略核心,管理网格队列状态和执行下单。
-
-**状态**: `StrategyState` enum: `WAITING_KLINE` / `OPENING` / `ACTIVE` / `STOPPED`
-
-**关键常量**:
-```java
-// 止盈条件单 order_type:仓位计划止盈止损,支持指定张数部分平仓
-private static final String ORDER_TYPE_CLOSE_LONG = "plan-close-long-position";
-private static final String ORDER_TYPE_CLOSE_SHORT = "plan-close-short-position";
-```
-
-**回调方法**:
-
-| 方法 | 触发源 | 逻辑 |
-|------|--------|------|
-| `onKline(closePrice, timestamp)` | CandlestickChannelHandler | 更新 lastKlinePrice → 计算 unrealizedPnl → WAITING_KLINE 时触发基底双开 → ACTIVE 时方向区分,一个K线只触发一个方向 |
-| `onPositionUpdate(contract, mode, size, entryPrice)` | PositionsChannelHandler | 基底首次成交记录入场价 + tryGenerateQueues → 仓位净减少时触反向市价单 → Map截断(>5) |
-| `onPositionClose(contract, side, pnl)` | PositionClosesChannelHandler | 累加已实现盈亏 → 检查停止条件 |
-| `onOrderUpdate(orderId, status, finishAs)` | OrdersChannelHandler | 条件单成交(finished+filled) → Map.remove 取止盈价 → placeTakeProfit |
-
-**processShortGrid / processLongGrid 核心逻辑**:
-
-| 步骤 | processShortGrid(空仓触发) | processLongGrid(多仓触发) |
-|------|---------------------------|---------------------------|
-| 匹配 | 收集 shortPriceQueue 中 > currentPrice 的元素 | 收集 longPriceQueue 中 < currentPrice 的元素 |
-| 本队补充 | 尾价 − step 循环递减 × matched.size() 次 | 尾价 + step 循环递增 × matched.size() 次 |
-| 对方队列 | 不再更新(队列转移已移除) | 不再更新(队列转移已移除) |
-| 保证金检查 | marginRatio ≥ 20% 则跳过挂单 | 同左 |
-| 挂新条件单 | 空仓条件单(止盈价=新short[0]−step→currentShortOrderIds) | 多仓条件单(止盈价=新long[0]+step→currentLongOrderIds) |
-| 对方守卫 | newLongFirst + step×2 < longEntryPrice → 挂多仓条件单 | newShortFirst − step×2 > shortEntryPrice → 挂空仓条件单 |
-
-**未实现盈亏计算** (`updateUnrealizedPnl()`):
-
-正向合约公式(含合约乘数):
-
-| 方向 | 公式 |
-|------|------|
-| 多仓 | 持仓量 × contractMultiplier × (计价价格 − 开仓均价) |
-| 空仓 | 持仓量(绝对值)× contractMultiplier × (开仓均价 − 计价价格) |
-
-计价价格由 `unrealizedPnlPriceMode` 决定:
-- `LAST_PRICE`:使用最新成交价(`lastKlinePrice`,每根 K 线更新)
-- `MARK_PRICE`:使用标记价格(通过 `setMarkPrice()` 外部注入,如未注入则回退到最新成交价)
-
-**保证金安全阀** (`isMarginSafe()`):
-- 实时查询 `positionInitialMargin / initialPrincipal`
-- 比例 ≥ marginRatioLimit(默认20%)→ 跳过开仓,队列照常更新
-- REST 查询失败 → 默认放行(避免因查询异常阻塞策略)
-
-**REST API 调用**:
-
-| 操作 | API | 方法 | 说明 |
-|------|-----|------|------|
-| 获取用户ID | `GET /account/detail` | `AccountApi.getAccountDetail()` | |
-| 切持仓模式 | `POST /futures/usdt/set_position_mode` | `FuturesApi.setPositionMode()` | |
-| 查仓位 | `GET /futures/usdt/positions` | `FuturesApi.listPositions()` | 遍历所有仓位,按合约过滤 |
-| 市价平仓 | `POST /futures/usdt/orders` | `FuturesApi.createFuturesOrder()` | reduce_only, IOC |
-| 设杠杆 | `POST /futures/usdt/dual_comp/positions/{contract}/leverage` | `FuturesApi.updateDualModePositionLeverageCall()` | 双向模式专用 |
-| 查账户 | `GET /futures/usdt/accounts` | `FuturesApi.listFuturesAccounts()` | 获取初始本金 |
-| 查市价 | `GET /futures/usdt/order_book` | `FuturesApi.listFuturesOrderBook()` | 获取合约实时市价(用于市价单 price="0" 的参照) |
-
----
-
-## GateChannelHandler 接口体系
-
-```
-GateChannelHandler (接口)
- ├── CandlestickChannelHandler (公开频道)
- └── AbstractPrivateChannelHandler (私有频道基类: HMAC-SHA512)
- ├── PositionsChannelHandler
- ├── PositionClosesChannelHandler
- └── OrdersChannelHandler
-```
-
-- **subscribe**: 发送订阅请求。私有 Handler 自动附加 auth 字段
-- **unsubscribe**: 发送取消订阅请求(私有频道也带签名认证)
-- **handleMessage**: 解析推送数据并回调 GateGridTradeService,返回 true 表示已处理
-- 消息路由: update/all 事件 → 遍历 channelHandlers → handler 内部二次匹配 channel 名 → 匹配成功回调并停止遍历
-
-### PositionsChannelHandler 完整推送字段(20个)
-
-| 字段 | 类型 | 描述 |
-|------|------|------|
-| contract | String | 合约名称 |
-| mode | String | 持仓模式:dual_long / dual_short |
-| size | String/Integer | 合约张数(正=多头,负=空头) |
-| entry_price | Float | 开仓均价 |
-| cross_leverage_limit | Float | 全仓模式下的杠杆倍数上限 |
-| history_pnl | Float | 已平仓的仓位总盈亏 |
-| history_point | Float | 已平仓的点卡总盈亏 |
-| last_close_pnl | Float | 最近一次平仓的盈亏 |
-| leverage | Integer | 杠杆倍数(0=全仓,正数=逐仓) |
-| leverage_max | Integer | 当前风险限额下允许的最大杠杆倍数 |
-| liq_price | Float | 爆仓价格 |
-| maintenance_rate | Float | 当前风险限额下维持保证金比例 |
-| margin | Float | 保证金 |
-| realised_pnl | Float | 已实现盈亏 |
-| realised_point | Float | 点卡已实现盈亏 |
-| risk_limit | Integer | 风险限额 |
-| time | Integer | 更新 unix 时间戳(秒) |
-| time_ms | Integer | 更新 unix 时间戳(毫秒) |
-| user | String | 用户 ID |
-| update_id | Integer | 消息序列号,每次推送 order 后自增1 |
-
-> 以上 20 个字段在 PositionsChannelHandler.handleMessage() 中通过 SLF4J 日志全部输出。
-> 回调给 GateGridTradeService.onPositionUpdate() 的仅有 mode、size、entryPrice 三个核心字段。
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
deleted file mode 100644
index 1889761..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import java.nio.charset.StandardCharsets;
-
-/**
- * 私有频道 WS 处理器的抽象基类,封装 HMAC-SHA512 签名认证与订阅/取消订阅逻辑。
- *
- * @author Administrator
- */
-@Slf4j
-public abstract class AbstractPrivateChannelHandler implements GateChannelHandler {
-
- private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
-
- private final String channelName;
- protected final String apiKey;
- protected final String apiSecret;
- private final String contract;
- private final GateGridTradeService gridTradeService;
-
- public AbstractPrivateChannelHandler(String channelName,
- String apiKey, String apiSecret,
- String contract,
- GateGridTradeService gridTradeService) {
- this.channelName = channelName;
- this.apiKey = apiKey;
- this.apiSecret = apiSecret;
- this.contract = contract;
- this.gridTradeService = gridTradeService;
- }
-
- /** @return 频道名称(如 "futures.positions") */
- @Override
- public String getChannelName() { return channelName; }
-
- /**
- * 发送带签名的订阅请求。
- *
- * <h3>请求格式</h3>
- * <pre>
- * {
- * "id": <唯一请求ID>,
- * "time": <unix时间戳(秒)>,
- * "channel":"futures.positions",
- * "event": "subscribe",
- * "payload":[userId, contract],
- * "auth": {"method":"api_key", "KEY":<APIKEY>, "SIGN":<HMAC-SHA512签名>}
- * }
- * </pre>
- */
- @Override
- public void subscribe(WebSocketClient ws) {
- long timeSec = System.currentTimeMillis() / 1000;
- JSONObject msg = buildAuthRequest("subscribe", buildUid(), timeSec);
- ws.send(msg.toJSONString());
- log.info("[{}] 订阅成功, 合约:{}", channelName, contract);
- }
-
- /**
- * 发送带签名的取消订阅请求,与 subscribe 结构一致。
- * payload: [contract],无 userId(取消订阅不需要用户ID)。
- */
- @Override
- public void unsubscribe(WebSocketClient ws) {
- long timeSec = System.currentTimeMillis() / 1000;
- JSONObject msg = new JSONObject();
- msg.put("id", timeSec * 1000000 + (System.currentTimeMillis() % 1000));
- msg.put("time", timeSec);
- msg.put("channel", channelName);
- msg.put("event", "unsubscribe");
- JSONArray payload = new JSONArray();
- payload.add(contract);
- msg.put("payload", payload);
- JSONObject auth = new JSONObject();
- auth.put("method", "api_key");
- auth.put("KEY", apiKey);
- auth.put("SIGN", hs512Sign("unsubscribe", timeSec));
- msg.put("auth", auth);
- ws.send(msg.toJSONString());
- log.info("[{}] 取消订阅成功, 合约:{}", channelName, contract);
- }
-
- /** @return 网格交易服务实例 */
- protected GateGridTradeService getGridTradeService() { return gridTradeService; }
- /** @return 当前订阅的合约名称 */
- protected String getContract() { return contract; }
-
- /**
- * 从策略服务获取用户 ID,用于私有频道订阅的 payload[0]。
- *
- * @return 用户 ID 字符串,获取失败返回空字符串
- */
- private String buildUid() {
- return gridTradeService != null && gridTradeService.getUserId() != null
- ? String.valueOf(gridTradeService.getUserId()) : "";
- }
-
- /**
- * 构建认证请求 JSON。
- * 包含 id、time、channel、event、payload[userId, contract]、auth 字段。
- *
- * @param event 事件类型("subscribe" / "unsubscribe")
- * @param uid 认证用户 ID
- * @param timeSec unix 时间戳(秒)
- * @return 完整的认证请求 JSONObject
- */
- private JSONObject buildAuthRequest(String event, String uid, long timeSec) {
- JSONObject msg = new JSONObject();
- msg.put("id", timeSec * 1000000 + (System.currentTimeMillis() % 1000));
- msg.put("time", timeSec);
- msg.put("channel", channelName);
- msg.put("event", event);
- JSONArray payload = new JSONArray();
- payload.add(uid);
- payload.add(contract);
- msg.put("payload", payload);
- JSONObject auth = new JSONObject();
- auth.put("method", "api_key");
- auth.put("KEY", apiKey);
- auth.put("SIGN", hs512Sign(event, timeSec));
- msg.put("auth", auth);
- return msg;
- }
-
- /**
- * HMAC-SHA512 签名计算。
- *
- * <h3>签名算法</h3>
- * <pre>
- * message = "channel={channelName}&event={event}&time={timeSec}"
- * SIGN = Hex(HmacSHA512(apiSecret(UTF-8), message(UTF-8)))
- * </pre>
- *
- * <h3>错误处理</h3>
- * 签名计算失败时返回空字符串(日志记录错误),不抛异常,
- * 避免阻塞 WebSocket 回调线程。
- *
- * @param event 事件类型
- * @param timeSec unix 时间戳(秒)
- * @return 十六进制签名字符串,失败返回 ""
- */
- protected String hs512Sign(String event, long timeSec) {
- try {
- String message = "channel=" + channelName + "&event=" + event + "&time=" + timeSec;
- Mac mac = Mac.getInstance("HmacSHA512");
- SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
- mac.init(spec);
- byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
- StringBuilder hex = new StringBuilder(hash.length * 2);
- for (byte b : hash) {
- hex.append(HEX_ARRAY[(b >> 4) & 0xF]);
- hex.append(HEX_ARRAY[b & 0xF]);
- }
- return hex.toString();
- } catch (Exception e) {
- log.error("[{}] 签名计算失败", channelName, e);
- return "";
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/GateChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/GateChannelHandler.java
deleted file mode 100644
index e24baff..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/GateChannelHandler.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler;
-
-import com.alibaba.fastjson.JSONObject;
-import org.java_websocket.client.WebSocketClient;
-
-/**
- * WebSocket 频道处理器接口。
- *
- * <p>每个 Gate 频道对应一个实现类。新增频道只需实现此接口,
- * 然后通过 {@code GateKlineWebSocketClient.addChannelHandler()} 注册即可。
- *
- * <h3>实现类</h3>
- * <ul>
- * <li>{@code CandlestickChannelHandler} — 公开频道,K 线数据</li>
- * <li>{@code AbstractPrivateChannelHandler} — 私有频道抽象基类(签名+认证)</li>
- * <li>{@code PositionsChannelHandler} — 私有频道,仓位更新</li>
- * <li>{@code PositionClosesChannelHandler} — 私有频道,平仓推送</li>
- * </ul>
- *
- * <h3>路由机制</h3>
- * {@code handleMessage()} 返回 {@code true} 表示消息已被该 handler 处理,
- * 路由循环会停止遍历。返回 {@code false} 表示不匹配(channel 名不相等)。
- *
- * @author Administrator
- */
-public interface GateChannelHandler {
-
- /** 频道名称,如 {@code "futures.candlesticks"} */
- String getChannelName();
-
- /** 发送订阅请求 */
- void subscribe(WebSocketClient ws);
-
- /** 发送取消订阅请求 */
- void unsubscribe(WebSocketClient ws);
-
- /**
- * 处理频道推送消息。
- *
- * @param response WebSocket 推送的完整 JSON
- * @return true 表示已处理(循环停止),false 表示频道不匹配(继续遍历下一个 handler)
- */
- boolean handleMessage(JSONObject response);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/AutoOrdersChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/AutoOrdersChannelHandler.java
deleted file mode 100644
index 972d2b6..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/AutoOrdersChannelHandler.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.AbstractPrivateChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-/**
- * 自动订单频道处理器(futures.autoorders)。
- *
- * <h3>数据用途</h3>
- * 订阅用户自动订单(条件单)更新推送。当条件单状态变更(已触发、已取消等)时,
- * 获得订单 ID、状态、触发信息等,可用于跟踪条件单生命周期。
- *
- * <h3>与 futures.orders 的区别</h3>
- * {@code futures.autoorders} 推送的是条件订单(价格触发单)的状态变更,
- * 而 {@code futures.orders} 推送的是普通订单(市价单、限价单)的成交/取消。
- *
- * <h3>关键推送字段</h3>
- * <ul>
- * <li>id:自动订单 ID</li>
- * <li>status:订单状态(open / finished / cancelled)</li>
- * <li>reason:变更原因</li>
- * <li>trigger.price / trigger.rule:触发条件</li>
- * <li>order_type:止盈/止损类型</li>
- * <li>trade_id:关联交易 ID</li>
- * </ul>
- *
- * <h3>注意</h3>
- * 此频道的 payload 仅需 [contract],无需 userId(与 futures.orders 不同)。
- *
- * @author Administrator
- */
-@Slf4j
-public class AutoOrdersChannelHandler extends AbstractPrivateChannelHandler {
-
- private static final String CHANNEL_NAME = "futures.autoorders";
-
- public AutoOrdersChannelHandler(String apiKey, String apiSecret,
- String contract,
- GateGridTradeService gridTradeService) {
- super(CHANNEL_NAME, apiKey, apiSecret, contract, gridTradeService);
- }
-
- /**
- * 发送订阅请求,payload 仅需 [contract](此频道不需要 userId)。
- */
- @Override
- public void subscribe(WebSocketClient ws) {
- long timeSec = System.currentTimeMillis() / 1000;
- JSONObject msg = new JSONObject();
- msg.put("id", timeSec * 1000000 + (System.currentTimeMillis() % 1000));
- msg.put("time", timeSec);
- msg.put("channel", CHANNEL_NAME);
- msg.put("event", "subscribe");
- JSONArray payload = new JSONArray();
- payload.add(getContract());
- msg.put("payload", payload);
- JSONObject auth = new JSONObject();
- auth.put("method", "api_key");
- auth.put("KEY", apiKey);
- auth.put("SIGN", hs512Sign("subscribe", timeSec));
- msg.put("auth", auth);
- ws.send(msg.toJSONString());
- log.info("[{}] 订阅成功, 合约:{}", CHANNEL_NAME, getContract());
- }
-
- @Override
- public boolean handleMessage(JSONObject response) {
- if (!CHANNEL_NAME.equals(response.getString("channel"))) {
- return false;
- }
- try {
- JSONArray resultArray = response.getJSONArray("result");
- if (resultArray == null || resultArray.isEmpty()) {
- return true;
- }
- for (int i = 0; i < resultArray.size(); i++) {
- JSONObject autoOrder = resultArray.getJSONObject(i);
- JSONObject initial = autoOrder.getJSONObject("initial");
- if (initial == null) {
- continue;
- }
- if (!getContract().equals(initial.getString("contract"))) {
- continue;
- }
- String orderId = String.valueOf(autoOrder.getLong("id"));
- String status = autoOrder.getString("status");
- String reason = autoOrder.getString("reason");
- String orderType = autoOrder.getString("order_type");
- String tradeId = autoOrder.getString("trade_id");
- JSONObject trigger = autoOrder.getJSONObject("trigger");
- String triggerPrice = trigger != null ? trigger.getString("price") : null;
- log.info("[{}] 自动订单更新, id:{}, status:{}, reason:{}, order_type:{}, trigger_price:{}, trade_id:{}",
- CHANNEL_NAME, orderId, status, reason, orderType, triggerPrice,
- tradeId);
- if (getGridTradeService() != null) {
- getGridTradeService().onAutoOrder(orderId, status, reason, orderType, tradeId);
- }
- }
- } catch (Exception e) {
- log.error("[{}] 处理数据失败", CHANNEL_NAME, e);
- }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
deleted file mode 100644
index fa05514..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.blackchain.service.DateUtil;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.GateChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import java.math.BigDecimal;
-
-/**
- * K 线频道处理器(futures.candlesticks)— 策略的唯一价格时间驱动源。
- *
- * <h3>定位</h3>
- * 订阅 1 分钟 K 线实时推送,每收到一根 K 线(不等待完结)即触发
- * {@link GateGridTradeService#onKline(BigDecimal)},由策略引擎决定是否开仓/止盈。
- *
- * <h3>订阅格式</h3>
- * 公开频道,无需认证签名。payload: {@code ["1m", contract]}。
- *
- * @author Administrator
- */
-@Slf4j
-public class CandlestickChannelHandler implements GateChannelHandler {
-
- private static final String CHANNEL_NAME = "futures.candlesticks";
- /** K 线周期,固定 1 分钟 */
- private static final String INTERVAL = "1m";
-
- /** 合约名称 */
- private final String contract;
- /** 网格交易服务,接收 K 线回调 */
- private final GateGridTradeService gridTradeService;
-
- /**
- * @param contract 合约名称(如 ETH_USDT)
- * @param gridTradeService 网格交易策略服务实例
- */
- public CandlestickChannelHandler(String contract, GateGridTradeService gridTradeService) {
- this.contract = contract;
- this.gridTradeService = gridTradeService;
- }
-
- /** @return 频道名称 "futures.candlesticks" */
- @Override
- public String getChannelName() { return CHANNEL_NAME; }
-
- /**
- * 发送 K 线频道订阅请求(公开频道,无需签名)。
- *
- * <h3>订阅格式</h3>
- * <pre>
- * {
- * "time": <unix时间戳(秒)>,
- * "channel": "futures.candlesticks",
- * "event": "subscribe",
- * "payload": ["1m", "{contract}"]
- * }
- * </pre>
- */
- @Override
- public void subscribe(WebSocketClient ws) {
- JSONObject msg = new JSONObject();
- msg.put("time", System.currentTimeMillis() / 1000);
- msg.put("channel", CHANNEL_NAME);
- msg.put("event", "subscribe");
- JSONArray payload = new JSONArray();
- payload.add(INTERVAL);
- payload.add(contract);
- msg.put("payload", payload);
- ws.send(msg.toJSONString());
- log.info("[{}] 订阅成功, 合约:{}, 周期:{}", CHANNEL_NAME, contract, INTERVAL);
- }
-
- /**
- * 发送 K 线频道取消订阅请求。
- */
- @Override
- public void unsubscribe(WebSocketClient ws) {
- JSONObject msg = new JSONObject();
- msg.put("time", System.currentTimeMillis() / 1000);
- msg.put("channel", CHANNEL_NAME);
- msg.put("event", "unsubscribe");
- JSONArray payload = new JSONArray();
- payload.add(INTERVAL);
- payload.add(contract);
- msg.put("payload", payload);
- ws.send(msg.toJSONString());
- log.info("[{}] 取消订阅成功", CHANNEL_NAME);
- }
-
- /**
- * 处理 K 线推送消息。
- *
- * <h3>数据提取</h3>
- * result[0] 中提取:
- * <ul>
- * <li>c(close):收盘价 → 传给 gridTradeService.onKline()</li>
- * <li>n(name):烛线名称(如 "1m_ETH_USDT")</li>
- * <li>t(time):烛线起始时间戳</li>
- * <li>w(window_close):烛线是否完结(仅日志输出,不做门控)</li>
- * </ul>
- *
- * <h3>注意</h3>
- * 不判断 w(已完结)——策略需要 tick 级实时响应价格变动,
- * 而非等 1 分钟烛线完结后才行动。
- *
- * @param response WebSocket 推送的完整 JSON
- * @return true 表示已处理(匹配成功)
- */
- @Override
- public boolean handleMessage(JSONObject response) {
- if (!CHANNEL_NAME.equals(response.getString("channel"))) {
- return false;
- }
- try {
- JSONArray resultArray = response.getJSONArray("result");
- if (resultArray == null || resultArray.isEmpty()) { log.warn("[{}] 数据为空", CHANNEL_NAME); return true; }
- JSONObject data = resultArray.getJSONObject(0);
- BigDecimal closePx = new BigDecimal(data.getString("c"));
-
-// log.info("========== Gate K线数据 ==========");
-// log.info("名称: {} 时间: {}", data.getString("n"), DateUtil.TimeStampToDateTime(data.getLong("t")));
-// log.info("收盘: {} 已完结: {}",data.getString("c"),data.getBooleanValue("w"));
-// log.info("==================================");
-
- if (gridTradeService != null) {
- gridTradeService.onKline(closePx);
- }
- } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java
deleted file mode 100644
index 3d15c45..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.AbstractPrivateChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * 订单频道处理器(futures.orders),接收订单更新推送并回调 {@link GateGridTradeService#onOrderUpdate}。
- * 回调内部通过 {@code GridElement.findByLongOrderId / findByShortOrderId} 匹配网格订单。
- *
- * @author Administrator
- */
-@Slf4j
-public class OrdersChannelHandler extends AbstractPrivateChannelHandler {
-
- private static final String CHANNEL_NAME = "futures.orders";
-
- public OrdersChannelHandler(String apiKey, String apiSecret,
- String contract,
- GateGridTradeService gridTradeService) {
- super(CHANNEL_NAME, apiKey, apiSecret, contract, gridTradeService);
- }
-
- @Override
- public boolean handleMessage(JSONObject response) {
- if (!CHANNEL_NAME.equals(response.getString("channel"))) {
- return false;
- }
- try {
- JSONArray resultArray = response.getJSONArray("result");
- if (resultArray == null || resultArray.isEmpty()) {
- return true;
- }
- for (int i = 0; i < resultArray.size(); i++) {
- JSONObject order = resultArray.getJSONObject(i);
- if (!getContract().equals(order.getString("contract"))) {
- continue;
- }
- String orderId = String.valueOf(order.getLong("id"));
- String status = order.getString("status");
- String finishAs = order.getString("finish_as");
- String updateId = order.getString("update_id");
-// log.info("[{}] 订单更新, id:{}, status:{}, finish_as:{}, price:{}, size:{},update_id:{}",
-// CHANNEL_NAME, orderId, status, finishAs,
-// order.get("price"), order.get("size"),updateId);
-// if (getGridTradeService() != null) {
-// getGridTradeService().onOrderUpdate(orderId, status, finishAs);
-// }
- }
- } catch (Exception e) {
- log.error("[{}] 处理数据失败", CHANNEL_NAME, e);
- }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
deleted file mode 100644
index c58ea39..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.AbstractPrivateChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-
-/**
- * 平仓频道处理器(futures.position_closes),接收平仓盈亏推送并回调 {@link GateGridTradeService#onPositionClose}。
- *
- * @author Administrator
- */
-@Slf4j
-public class PositionClosesChannelHandler extends AbstractPrivateChannelHandler {
-
- private static final String CHANNEL_NAME = "futures.position_closes";
-
- /**
- * @param apiKey Gate API v4 密钥,用于签名认证
- * @param apiSecret Gate API v4 签名密钥
- * @param contract 合约名称(如 ETH_USDT)
- * @param gridTradeService 网格交易策略服务实例
- */
- public PositionClosesChannelHandler(String apiKey, String apiSecret,
- String contract,
- GateGridTradeService gridTradeService) {
- super(CHANNEL_NAME, apiKey, apiSecret, contract, gridTradeService);
- }
-
- /**
- * 处理平仓推送消息。
- *
- * <h3>数据提取</h3>
- * result 数组中每个元素包含:
- * <ul>
- * <li>contract:合约名称</li>
- * <li>side:平仓方向("long" / "short")</li>
- * <li>pnl:本次平仓的盈亏金额(字符串格式,如 "+0.2" / "-0.1")</li>
- * </ul>
- *
- * <h3>数据处理</h3>
- * 按合约名称过滤 → 提取 pnl 和 side → 调用 gridTradeService.onPositionClose() 累加盈亏。
- * pnl 来自服务端,不受本地计算误差影响。
- *
- * @param response WebSocket 推送的完整 JSON
- * @return true 表示已处理(匹配成功)
- */
- @Override
- public boolean handleMessage(JSONObject response) {
- if (!CHANNEL_NAME.equals(response.getString("channel"))) {
- return false;
- }
- try {
- JSONArray resultArray = response.getJSONArray("result");
- if (resultArray == null || resultArray.isEmpty()) {
- return true;
- }
- for (int i = 0; i < resultArray.size(); i++) {
- JSONObject item = resultArray.getJSONObject(i);
- if (!getContract().equals(item.getString("contract"))) {
- continue;
- }
- BigDecimal pnl = new BigDecimal(item.getString("pnl"));
- String side = item.getString("side");
- log.info("[{}] 平仓更新, 方向:{}, 盈亏:{}", CHANNEL_NAME, side, pnl);
- if (getGridTradeService() != null) {
- getGridTradeService().onPositionClose(getContract(), side, pnl);
- }
- }
- } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
deleted file mode 100644
index 9608782..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.AbstractPrivateChannelHandler;
-import io.gate.gateapi.models.Position;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-
-/**
- * 仓位频道处理器(futures.positions),接收仓位更新推送并回调 {@link GateGridTradeService#onPositionUpdate}。
- *
- * @author Administrator
- */
-@Slf4j
-public class PositionsChannelHandler extends AbstractPrivateChannelHandler {
-
- private static final String CHANNEL_NAME = "futures.positions";
-
- /**
- * @param apiKey Gate API v4 密钥,用于签名认证
- * @param apiSecret Gate API v4 签名密钥
- * @param contract 合约名称(如 ETH_USDT)
- * @param gridTradeService 网格交易策略服务实例
- */
- public PositionsChannelHandler(String apiKey, String apiSecret,
- String contract,
- GateGridTradeService gridTradeService) {
- super(CHANNEL_NAME, apiKey, apiSecret, contract, gridTradeService);
- }
-
- @Override
- public boolean handleMessage(JSONObject response) {
- if (!CHANNEL_NAME.equals(response.getString("channel"))) {
- return false;
- }
- try {
- JSONArray resultArray = response.getJSONArray("result");
- if (resultArray == null || resultArray.isEmpty()) {
- return true;
- }
- for (int i = 0; i < resultArray.size(); i++) {
- JSONObject pos = resultArray.getJSONObject(i);
- if (!getContract().equals(pos.getString("contract"))) {
- continue;
- }
- String modeStr = pos.getString("mode");
- Position.ModeEnum mode = Position.ModeEnum.fromValue(modeStr);
- BigDecimal size = new BigDecimal(pos.getString("size"));
- BigDecimal entryPrice = new BigDecimal(pos.getString("entry_price"));
- log.info("[{}] 持仓更新, 合约:{}, 模式:{}, 数量:{}, 入场价:{}, 全仓杠杆上限:{}, 历史盈亏:{}, 历史点卡:{}, 最近平仓盈亏:{}, 杠杆:{}, 最大杠杆:{}, 爆仓价:{}, 维持保证金率:{}, 保证金:{}, 已实现盈亏:{}, 点卡已实现盈亏:{}, 风险限额:{}, 时间:{}, 时间ms:{}, 用户:{}, 更新ID:{}",
- CHANNEL_NAME, pos.getString("contract"), modeStr, size, entryPrice,
- pos.get("cross_leverage_limit"), pos.get("history_pnl"), pos.get("history_point"),
- pos.get("last_close_pnl"), pos.get("leverage"), pos.get("leverage_max"),
- pos.get("liq_price"), pos.get("maintenance_rate"), pos.get("margin"),
- pos.get("realised_pnl"), pos.get("realised_point"), pos.get("risk_limit"),
- pos.get("time"), pos.get("time_ms"), pos.get("user"), pos.get("update_id"));
- if (getGridTradeService() != null) {
- getGridTradeService().onPositionUpdate(getContract(), mode, size, entryPrice);
- }
- }
- } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java
deleted file mode 100644
index 961a877..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.AbstractPrivateChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-
-/**
- * 用户私有成交频道处理器(futures.usertrades),接收成交推送并回调 {@link GateGridTradeService#onUserTrade}。
- *
- * @author Administrator
- */
-@Slf4j
-public class UserTradesChannelHandler extends AbstractPrivateChannelHandler {
-
- private static final String CHANNEL_NAME = "futures.usertrades";
-
- public UserTradesChannelHandler(String apiKey, String apiSecret,
- String contract,
- GateGridTradeService gridTradeService) {
- super(CHANNEL_NAME, apiKey, apiSecret, contract, gridTradeService);
- }
-
- @Override
- public boolean handleMessage(JSONObject response) {
- if (!CHANNEL_NAME.equals(response.getString("channel"))) {
- return false;
- }
- try {
- JSONArray resultArray = response.getJSONArray("result");
- if (resultArray == null || resultArray.isEmpty()) {
- return true;
- }
- for (int i = 0; i < resultArray.size(); i++) {
- JSONObject trade = resultArray.getJSONObject(i);
- String contract = trade.getString("contract");
- if (!getContract().equals(contract)) {
- continue;
- }
- String id = trade.getString("id");
- String orderId = trade.getString("order_id");
- String size = trade.getString("size");
- BigDecimal price = trade.getBigDecimal("price");
- String role = trade.getString("role");
- BigDecimal fee = trade.getBigDecimal("fee");
- String text = trade.getString("text");
-// log.info("[{}] 成交更新, id:{}, order_id:{}, price:{}, size:{}, role:{}, fee:{}, text:{}",
-// CHANNEL_NAME, id, orderId, price, size, role, fee, text);
-// if (getGridTradeService() != null) {
-// getGridTradeService().onUserTrade(contract, orderId, price, size, role, fee);
-// }
- }
- } catch (Exception e) {
- log.error("[{}] 处理数据失败", CHANNEL_NAME, e);
- }
- return true;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/controller/MemberQuickBuySaleController.java b/src/main/java/com/xcong/excoin/modules/home/controller/MemberQuickBuySaleController.java
deleted file mode 100644
index ee8cbfb..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/controller/MemberQuickBuySaleController.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.xcong.excoin.modules.home.controller;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-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.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.alibaba.druid.util.StringUtils;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.home.dto.MemberQuickBuySaleCommitDto;
-import com.xcong.excoin.modules.home.dto.MemberQuickBuySaleDto;
-import com.xcong.excoin.modules.home.service.MemberQuickBuySaleService;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.service.MemberService;
-
-import cn.hutool.crypto.SecureUtil;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.extern.slf4j.Slf4j;
-
-@RestController
-@Slf4j
-@RequestMapping(value = "/api/quick")
-@Api(value = "MemberQuickBuySaleController", tags = "USDT快捷买卖类")
-public class MemberQuickBuySaleController {
-
- @Autowired
- MemberQuickBuySaleService memberQuickBuySaleService;
- @Autowired
- MemberService memberService;
-
- @ApiOperation(value = "recharge", notes = "USDT快速充值")
- @RequestMapping(value = "/recharge", method = RequestMethod.POST)
- public Result recharge(@RequestBody @Valid MemberQuickBuySaleDto memberQuickBuySaleDto) {
- log.info("入参----->{}", memberQuickBuySaleDto);
- //获取用户ID
- MemberEntity member = LoginUserUtils.getAppLoginUser();
- log.info("查询到的会员----->{}", member);
- // 验证是否实名认证
- //if (!MemberEntity.CERTIFY_STATUS_Y.equals(member.getCertifyStatus())) {
- // return Result.fail("请先实名认证");
- //}
- String tradePasswordWeb = memberQuickBuySaleDto.getTradePassword();
-
- // 验证支付密码
- String tradePassword = member.getTradePassword();
-
- log.info("入参交易密码{},用户设置的交易密码{}", tradePasswordWeb,tradePassword);
- if (StringUtils.isEmpty(tradePassword)) {
- return Result.fail("请先配置交易密码");
- }
- if (StringUtils.isEmpty(tradePasswordWeb)) {
- return Result.fail("请输入交易密码");
- }
- // 验证交易密码
- if (!tradePassword.equals(SecureUtil.md5(tradePasswordWeb))) {
- return Result.fail("请输入正确的交易密码");
- }
- return memberQuickBuySaleService.recharge(member, memberQuickBuySaleDto);
- }
-
-
- @ApiOperation(value = "commitPay", notes = "USDT充值支付确认")
- @RequestMapping(value = "/commitPay", method = RequestMethod.POST)
- public Result commitPay(@RequestBody @Valid MemberQuickBuySaleCommitDto memberQuickBuySaleCommitDto) {
- return memberQuickBuySaleService.commitPay(memberQuickBuySaleCommitDto);
- }
-
- @ApiOperation(value = "selectById", notes = "查询单个买卖记录")
- @GetMapping(value = "/selectById/{id}")
- public Result selectById(@PathVariable(value = "id") Long id) {
- return memberQuickBuySaleService.selectById(id);
- }
-
- @ApiOperation(value = "selectAll", notes = "查询用户所有的买卖记录")
- @GetMapping(value = "/selectAll")
- public Result selectAll(@RequestParam(value = "type") String type) {
- return memberQuickBuySaleService.selectAll(type);
- }
-
- @ApiOperation(value = "cancel", notes = "充值撤销")
- @GetMapping(value = "/cancel")
- public Result cancel(@RequestParam(value = "id") Long id) {
- return memberQuickBuySaleService.cancelRecharge(id);
- }
-
- @ApiOperation(value = "sell", notes = "USDT快速卖出")
- @RequestMapping(value = "/sell", method = RequestMethod.POST)
- public Result sell(@RequestBody @Valid MemberQuickBuySaleDto memberQuickBuySaleDto) {
- // 获取当前登录用户
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberService.getById(memberId);
- if (!MemberEntity.CERTIFY_STATUS_Y.equals(member.getCertifyStatus())) {
- return Result.fail("请先实名认证");
- }
- String tradePasswordWeb = memberQuickBuySaleDto.getTradePassword();
- // 验证支付密码
- String tradePassword = member.getTradePassword();
-
- log.info("入参交易密码{},用户设置的交易密码{}", tradePasswordWeb,tradePassword);
- if (StringUtils.isEmpty(tradePassword)) {
- return Result.fail("请先配置交易密码");
- }
- if (StringUtils.isEmpty(tradePasswordWeb)) {
- return Result.fail("请输入交易密码");
- }
- // 验证交易密码
- if (!tradePassword.equals(SecureUtil.md5(tradePasswordWeb))) {
- return Result.fail("请输入正确的交易密码");
- }
- return memberQuickBuySaleService.sell(member,memberQuickBuySaleDto);
- }
-
- @ApiOperation(value = "cancelSell", notes = "提现撤销")
- @GetMapping(value = "/cancelSell")
- public Result cancelSell(@RequestParam(value = "id") Long id) {
- return memberQuickBuySaleService.cancelSell(id);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/dao/MemberQuickBuySaleDao.java b/src/main/java/com/xcong/excoin/modules/home/dao/MemberQuickBuySaleDao.java
deleted file mode 100644
index 9f0f27f..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/dao/MemberQuickBuySaleDao.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.xcong.excoin.modules.home.dao;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.home.entity.MemberQuickBuySaleEntity;
-
-public interface MemberQuickBuySaleDao extends BaseMapper<MemberQuickBuySaleEntity> {
-
- MemberQuickBuySaleEntity selectByIdAndMemberId(@Param("memberId")Long memberId,@Param("id")Long id);
-
- int updateQuickBuySaleTimeOut();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/dto/MemberQuickBuySaleCommitDto.java b/src/main/java/com/xcong/excoin/modules/home/dto/MemberQuickBuySaleCommitDto.java
deleted file mode 100644
index 3d3a550..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/dto/MemberQuickBuySaleCommitDto.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.home.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberQuickBuySaleCommitDto", description = "确认快捷买入接收参数")
-public class MemberQuickBuySaleCommitDto {
-
- @NotNull(message = "订单id不能为空")
- @ApiModelProperty(value = "主键",example = "1")
- private Long id;
-
- @NotNull(message = "付款方式不能为空")
- @ApiModelProperty(value = "付款方式 1-支付宝2-微信3-银行卡",example = "1")
- private int paymentType;
-
- @NotNull(message = "收款账号不能为空")
- @ApiModelProperty(value = "收款账号",example = "13000000000")
- private String paymentAccount;
-
- @NotNull(message = "收款人姓名不能为空")
- @ApiModelProperty(value = "收款人姓名",example = "张三")
- private String paymentName;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/dto/MemberQuickBuySaleDto.java b/src/main/java/com/xcong/excoin/modules/home/dto/MemberQuickBuySaleDto.java
deleted file mode 100644
index 4e48a48..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/dto/MemberQuickBuySaleDto.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.home.dto;
-
-import java.math.BigDecimal;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "会员快捷买入卖出参数接收类", description = "会员快捷买入卖出参数接收类")
-public class MemberQuickBuySaleDto {
-
- @NotNull(message = "金额不能为空")
- @ApiModelProperty(value = "金额(人民币)",example = "700")
- private BigDecimal amountCny;
-
- @NotNull(message = "金额不能为空")
- @ApiModelProperty(value = "金额(USDT)",example = "100")
- private BigDecimal amountUsdt;
-
- @ApiModelProperty(value = "单价",example = "7")
- private BigDecimal unitPrice;
-
- @NotNull(message = "交易密码不能为空")
- @ApiModelProperty(value = "交易密码",example = "123456")
- private String tradePassword;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/entity/MemberQuickBuySaleEntity.java b/src/main/java/com/xcong/excoin/modules/home/entity/MemberQuickBuySaleEntity.java
deleted file mode 100644
index 88ca2bc..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/entity/MemberQuickBuySaleEntity.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.xcong.excoin.modules.home.entity;
-
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-@EqualsAndHashCode(callSuper = true)
-@Data
-@TableName("member_quick_buy_sale")
-public class MemberQuickBuySaleEntity extends BaseEntity{
- /**
- * 订单状态 1-新建
- */
- public static final Integer CHARGE_STATUS_CREATE = 1;
-
- /**
- * 订单状态 2-已付款
- */
- public static final Integer CHARGE_STATUS_PAID = 2;
-
- /**
- * 订单状态 3-已审核
- */
- public static final Integer CHARGE_STATUS_CHECKED = 3;
-
- /**
- * 订单状态 4-撤单
- */
- public static final Integer CHARGE_STATUS_CANCEL_USER = 4;
-
- /**
- * 订单状态 5-系统取消
- */
- public static final Integer CHARGE_STATUS_CANCEL_SYSTEM = 5;
-
-
- private static final long serialVersionUID = 1L;
- /**
- * 用户Id
- */
- private Long memberId;
- /**
- * 金额(人民币)
- */
- private BigDecimal amountCny;
- /**
- * 金额(USDT)
- */
- private BigDecimal amountUsdt;
- /**
- * 付款方式 1-支付宝2-微信3-银行卡
- */
- private Integer paymentType;
- /**
- * 收款账号
- */
- private String paymentAccount;
- /**
- * 收款人姓名
- */
- private String paymentName;
- /**
- * 支付码
- */
- private String paymentCode;
- /**
- * 单价
- */
- private BigDecimal unitPrice;
- /**
- * 订单状态 1-新建2-已付款3-已审核4-撤单5-系统取消
- */
- private int orderStatus;
- /**
- * 订单编号
- */
- private String orderNo;
- /**
- * 订单类型 B买入 S卖出
- */
- private String orderType;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/mapper/MemberQuickBuySaleEntityMapper.java b/src/main/java/com/xcong/excoin/modules/home/mapper/MemberQuickBuySaleEntityMapper.java
deleted file mode 100644
index c79e48e..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/mapper/MemberQuickBuySaleEntityMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.home.mapper;
-
-import java.util.List;
-
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import com.xcong.excoin.modules.home.dto.MemberQuickBuySaleDto;
-import com.xcong.excoin.modules.home.entity.MemberQuickBuySaleEntity;
-import com.xcong.excoin.modules.home.vo.MemberQuickBuySaleDetailVo;
-
-
-@Mapper
-public abstract class MemberQuickBuySaleEntityMapper {
-
- public static final MemberQuickBuySaleEntityMapper INSTANCE = Mappers.getMapper(MemberQuickBuySaleEntityMapper.class);
-
- public abstract MemberQuickBuySaleDetailVo entityToVo(MemberQuickBuySaleEntity memberQuickBuySaleEntity);
-
- public abstract MemberQuickBuySaleEntity dtoToEntity(MemberQuickBuySaleDto dto);
-
- public abstract List<MemberQuickBuySaleDetailVo> entityListToVoList(List<MemberQuickBuySaleEntity> memberQuickBuySaleEntityList);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/service/MemberQuickBuySaleService.java b/src/main/java/com/xcong/excoin/modules/home/service/MemberQuickBuySaleService.java
deleted file mode 100644
index 3256044..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/service/MemberQuickBuySaleService.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.modules.home.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.home.dto.MemberQuickBuySaleCommitDto;
-import com.xcong.excoin.modules.home.dto.MemberQuickBuySaleDto;
-import com.xcong.excoin.modules.home.entity.MemberQuickBuySaleEntity;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-
-public interface MemberQuickBuySaleService extends IService<MemberQuickBuySaleEntity> {
-
- public Result recharge(MemberEntity member,MemberQuickBuySaleDto memberQuickBuySaleDto);
-
- public Result commitPay(MemberQuickBuySaleCommitDto memberQuickBuySaleCommitDto);
-
- public Result selectById(Long id);
-
- public Result selectAll(String type);
-
- public Result cancelRecharge(Long id);
-
- public Result sell(MemberEntity member,MemberQuickBuySaleDto memberQuickBuySaleDto);
-
- public Result cancelSell(Long id);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/service/impl/MemberQuickBuySaleServiceImpl.java b/src/main/java/com/xcong/excoin/modules/home/service/impl/MemberQuickBuySaleServiceImpl.java
deleted file mode 100644
index fd6273b..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/service/impl/MemberQuickBuySaleServiceImpl.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package com.xcong.excoin.modules.home.service.impl;
-
-import java.math.BigDecimal;
-import java.util.Date;
-import java.util.List;
-
-import javax.annotation.Resource;
-
-import com.xcong.excoin.utils.ThreadPoolUtils;
-import com.xcong.excoin.utils.dingtalk.DingTalkType;
-import org.springframework.stereotype.Service;
-
-import com.alibaba.druid.util.StringUtils;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.home.dao.MemberQuickBuySaleDao;
-import com.xcong.excoin.modules.home.dto.MemberQuickBuySaleCommitDto;
-import com.xcong.excoin.modules.home.dto.MemberQuickBuySaleDto;
-import com.xcong.excoin.modules.home.entity.MemberQuickBuySaleEntity;
-import com.xcong.excoin.modules.home.mapper.MemberQuickBuySaleEntityMapper;
-import com.xcong.excoin.modules.home.service.MemberQuickBuySaleService;
-import com.xcong.excoin.modules.home.vo.MemberQuickBuySaleDetailVo;
-import com.xcong.excoin.modules.home.vo.MemberQuickBuySaleVo;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.dao.MemberPaymentMethodDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberPaymentMethodEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-import com.xcong.excoin.modules.platform.dao.PlatformPaymentMethodDao;
-import com.xcong.excoin.modules.platform.entity.PlatformPaymentMethodEntity;
-
-@Service
-public class MemberQuickBuySaleServiceImpl extends ServiceImpl<MemberQuickBuySaleDao, MemberQuickBuySaleEntity> implements MemberQuickBuySaleService {
-
- @Resource
- MemberDao memberDao;
- @Resource
- MemberQuickBuySaleDao memberQuickBuySaleDao;
- @Resource
- MemberWalletCoinDao memberWalletCoinDao;
- @Resource
- MemberPaymentMethodDao memberPaymentMethodDao;
- @Resource
- PlatformPaymentMethodDao platformPaymentMethodDao;
-
- @Override
- public Result recharge(MemberEntity member, MemberQuickBuySaleDto memberQuickBuySaleDto) {
- // 生成订单号
- Long timestamp = System.currentTimeMillis();
- int random = (int) (Math.random() * 10);
- String chargeNo = String.valueOf(timestamp).substring(2) + random;
- // 插入订单表
- MemberQuickBuySaleEntity memberQuickBuySaleEntity = new MemberQuickBuySaleEntity();
- memberQuickBuySaleEntity.setOrderStatus(1);
- memberQuickBuySaleEntity.setMemberId(member.getId());
- memberQuickBuySaleEntity.setAmountUsdt(memberQuickBuySaleDto.getAmountUsdt());
- memberQuickBuySaleEntity.setAmountCny(memberQuickBuySaleDto.getAmountCny());
- memberQuickBuySaleEntity.setUnitPrice(memberQuickBuySaleDto.getUnitPrice());
- memberQuickBuySaleEntity.setCreateTime(new Date());
- memberQuickBuySaleEntity.setOrderNo(chargeNo);
- memberQuickBuySaleEntity.setOrderType("B");
- // 支付码 ID+四位随机数
- int ran = (int) (Math.random() * 10000000);
- memberQuickBuySaleEntity.setPaymentCode(ran + "");
-
- memberQuickBuySaleDao.insert(memberQuickBuySaleEntity);
- MemberQuickBuySaleVo memberQuickBuySaleVo = new MemberQuickBuySaleVo();
- memberQuickBuySaleVo.setId(memberQuickBuySaleEntity.getId());
- // 返回前台付款方式
- return Result.ok("提交成功", memberQuickBuySaleVo);
- }
-
- @Override
- public Result commitPay(MemberQuickBuySaleCommitDto memberQuickBuySaleCommitDto) {
- // 用户提交支付确认 将状态改为付款中
- MemberQuickBuySaleEntity memberQuickBuySaleEntity = new MemberQuickBuySaleEntity();
- memberQuickBuySaleEntity.setId(memberQuickBuySaleCommitDto.getId());
- memberQuickBuySaleEntity.setOrderStatus(2);
- memberQuickBuySaleEntity.setPaymentAccount(memberQuickBuySaleCommitDto.getPaymentAccount());
- memberQuickBuySaleEntity.setPaymentName(memberQuickBuySaleCommitDto.getPaymentName());
-
- memberQuickBuySaleDao.updateById(memberQuickBuySaleEntity);
-
- ThreadPoolUtils.sendDingTalk(1);
- return Result.ok("确认成功");
- }
-
- @Override
- public Result selectById(Long id) {
- MemberQuickBuySaleEntity memberQuickBuySaleEntity = memberQuickBuySaleDao.selectById(id);
- MemberQuickBuySaleDetailVo memberQuickBuySaleDetailVo = MemberQuickBuySaleEntityMapper.INSTANCE.entityToVo(memberQuickBuySaleEntity);
- // 收款信息
- QueryWrapper<PlatformPaymentMethodEntity> queryWrapper = new QueryWrapper<>();
- queryWrapper.eq("status", "1");
- List<PlatformPaymentMethodEntity> paymentMethodList = platformPaymentMethodDao.selectList(queryWrapper);
- // 随机一个
- if (CollectionUtils.isEmpty(paymentMethodList)) {
- return Result.fail("收款方式为空");
- }
- memberQuickBuySaleDetailVo.setPlatforPaymentMethodList(paymentMethodList);
- long startTime = memberQuickBuySaleEntity.getCreateTime().getTime();
- long nowTime = new Date().getTime();
- long third = 30 * 60 * 1000;
- memberQuickBuySaleDetailVo.setTimeLeft((third - nowTime + startTime) / 1000);
- return Result.ok(memberQuickBuySaleDetailVo);
- }
-
- @Override
- public Result selectAll(String type) {
- MemberEntity member = LoginUserUtils.getAppLoginUser();
- QueryWrapper<MemberQuickBuySaleEntity> queryWrapper = new QueryWrapper<>();
- queryWrapper.eq("member_id", member.getId());
- if (!StringUtils.isEmpty(type)) {
- queryWrapper.eq("order_type", type);
- }
- queryWrapper.orderByDesc("id");
- List<MemberQuickBuySaleEntity> memberQuickBuySaleEntityList = memberQuickBuySaleDao.selectList(queryWrapper);
- List<MemberQuickBuySaleDetailVo> memberQuickBuySaleDetailVoList = MemberQuickBuySaleEntityMapper.INSTANCE.entityListToVoList(memberQuickBuySaleEntityList);
- return Result.ok(memberQuickBuySaleDetailVoList);
- }
-
- @Override
- public Result sell(MemberEntity member, MemberQuickBuySaleDto memberQuickBuySaleDto) {
- // 判断是否存在足够余额
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(member.getId(), CoinTypeEnum.USDT.toString());
- // 判断是否存在足够余额
- if (walletCoin == null) {
- return Result.fail("您当前可用USDT额度不够");
- }
- BigDecimal extractUsdt = memberQuickBuySaleDto.getAmountUsdt();
- if (extractUsdt == null) {
- return Result.fail("请输入提币量");
- }
- // 判断是否足够
- System.out.println("提币数:" + extractUsdt.doubleValue() + " 可用:" + walletCoin.getAvailableBalance());
- if (extractUsdt.compareTo(walletCoin.getAvailableBalance()) == 1) {
- return Result.fail("您当前可用USDT额度不够");
- }
-
- // 判断是否存在收款方式
- List<MemberPaymentMethodEntity> payMentMethodList = memberPaymentMethodDao.selectByMemberId(member.getId());
- if (CollectionUtils.isEmpty(payMentMethodList)) {
- return Result.fail("请配置收款方式");
- }
- // 冻结可用额度
- int i = memberWalletCoinDao.updateFrozenBalance(member.getId(),
- walletCoin.getId(), extractUsdt);
- if (i <= 0) {
- return Result.fail("可用USDT余额不足");
- }
-
- // 生成订单号
- Long timestamp = System.currentTimeMillis();
- int random = (int) (Math.random() * 10);
- String chargeNo = String.valueOf(timestamp).substring(2) + random;
- // 插入订单表
- MemberQuickBuySaleEntity memberQuickBuySaleEntity = new MemberQuickBuySaleEntity();
- memberQuickBuySaleEntity.setOrderStatus(1);
- memberQuickBuySaleEntity.setMemberId(member.getId());
- memberQuickBuySaleEntity.setAmountUsdt(memberQuickBuySaleDto.getAmountUsdt());
- memberQuickBuySaleEntity.setAmountCny(memberQuickBuySaleDto.getAmountCny());
- memberQuickBuySaleEntity.setOrderNo(chargeNo);
- memberQuickBuySaleEntity.setOrderType("S");
- // 支付码 ID+四位随机数
- int ran = (int) (Math.random() * 10000000);
- memberQuickBuySaleEntity.setPaymentCode(ran + "");
-
- memberQuickBuySaleDao.insert(memberQuickBuySaleEntity);
-
- ThreadPoolUtils.sendDingTalk(2);
- return Result.ok("下单成功");
- }
-
- @Override
- public Result cancelRecharge(Long id) {
- // 获取当前登录用户
- MemberEntity member = LoginUserUtils.getAppLoginUser();
- MemberQuickBuySaleEntity memberQuickBuySaleEntity = memberQuickBuySaleDao.selectByIdAndMemberId(member.getId(), id);
- memberQuickBuySaleEntity.setOrderStatus(MemberQuickBuySaleEntity.CHARGE_STATUS_CANCEL_USER);
- memberQuickBuySaleDao.updateById(memberQuickBuySaleEntity);
- return Result.ok("成功");
- }
-
- @Override
- public Result cancelSell(Long id) {
- // 获取当前登录用户
- MemberEntity member = LoginUserUtils.getAppLoginUser();
- MemberQuickBuySaleEntity memberQuickBuySaleEntity = memberQuickBuySaleDao.selectByIdAndMemberId(member.getId(), id);
- if (memberQuickBuySaleEntity != null) {
- memberQuickBuySaleEntity.setOrderStatus(MemberQuickBuySaleEntity.CHARGE_STATUS_CANCEL_USER);
- memberQuickBuySaleDao.updateById(memberQuickBuySaleEntity);
-
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(member.getId(), CoinTypeEnum.USDT.toString());
- // 冻结资金返回可用
- int i = memberWalletCoinDao.subFrozenBalance(member.getId(),
- walletCoin.getId(), memberQuickBuySaleEntity.getAmountUsdt());
- if (i < 0) {
- return Result.fail("撤单失败");
- }
- return Result.ok("成功");
- } else {
- return Result.fail("订单不存在");
- }
-
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/vo/MemberQuickBuySaleDetailVo.java b/src/main/java/com/xcong/excoin/modules/home/vo/MemberQuickBuySaleDetailVo.java
deleted file mode 100644
index db8e91f..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/vo/MemberQuickBuySaleDetailVo.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.modules.home.vo;
-
-import java.math.BigDecimal;
-import java.util.Date;
-import java.util.List;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.xcong.excoin.modules.platform.entity.PlatformPaymentMethodEntity;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-@Data
-@ApiModel(value = "会员快捷买入卖出", description = "会员快捷买入卖出类")
-public class MemberQuickBuySaleDetailVo {
-
- @ApiModelProperty(value = "订单Id")
- private Long id;
- @ApiModelProperty(value = "用户id")
- private Long memberId;
- @ApiModelProperty(value = "金额(人民币)")
- private BigDecimal amountCny;
- @ApiModelProperty(value = "金额(USDT)")
- private BigDecimal amountUsdt;
- @ApiModelProperty(value = "付款方式 1-支付宝2-微信3-银行卡")
- private Integer paymentType;
- @ApiModelProperty(value = "支付码")
- private String paymentCode;
- @ApiModelProperty(value = "单价")
- private BigDecimal unitPrice;
- @ApiModelProperty(value = "订单状态 1-新建2-已付款3-已审核4-撤单5-系统取消")
- private int orderStatus;
- @ApiModelProperty(value = "订单编号")
- private String orderNo;
- @ApiModelProperty(value = "订单类型 B买入 S卖出")
- private String orderType;
- @ApiModelProperty(value = "剩余时间")
- private Long timeLeft;
- @ApiModelProperty(value = "下单时间")
- @JsonFormat(pattern = "MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date createTime;
- @ApiModelProperty(value = "平台收款方式")
- private List<PlatformPaymentMethodEntity> platforPaymentMethodList;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/home/vo/MemberQuickBuySaleVo.java b/src/main/java/com/xcong/excoin/modules/home/vo/MemberQuickBuySaleVo.java
deleted file mode 100644
index 6d41454..0000000
--- a/src/main/java/com/xcong/excoin/modules/home/vo/MemberQuickBuySaleVo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xcong.excoin.modules.home.vo;
-
-import java.util.List;
-
-import com.xcong.excoin.modules.platform.entity.PlatformPaymentMethodEntity;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-@Data
-@ApiModel(value = "会员快捷买入卖出", description = "会员快捷买入卖出类")
-public class MemberQuickBuySaleVo {
-
- @ApiModelProperty(value = "订单Id")
- private Long id;
- @ApiModelProperty(value = "剩余时间")
- private Long timeLeft;
- @ApiModelProperty(value = "平台收款方式")
- private List<PlatformPaymentMethodEntity> platforPaymentMethodList;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/controller/MemberController.java b/src/main/java/com/xcong/excoin/modules/member/controller/MemberController.java
deleted file mode 100644
index c2a3f6e..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/controller/MemberController.java
+++ /dev/null
@@ -1,365 +0,0 @@
-package com.xcong.excoin.modules.member.controller;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-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;
-
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.member.parameter.dto.MemberAddCoinAddressDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberAuthenticationDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberBindEmailDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberBindPhoneDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberDelCoinAddressDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberDelPaymethodDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberForgetPwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberPaymethodDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberSubmitCoinApplyDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdatePwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdateTradePwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdateTradersPwdTimeDto;
-import com.xcong.excoin.modules.member.parameter.vo.AppVersionListVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberAuthenticationInfoVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberAvivableCoinInfoVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberCoinAddressCountListVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberCoinAddressListVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberCoinInfoListVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberInfoVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberPaymethodDetailListVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberPaymethodDetailVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberPersonCenterInfoVo;
-import com.xcong.excoin.modules.member.parameter.vo.MemberSendCodeWayVo;
-import com.xcong.excoin.modules.member.service.MemberService;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * 用户类
- *
- * @author wzy
- * @date 2020-05-18
- **/
-@Slf4j
-@Api(value = "个人中心接口", tags = "个人中心接口")
-@RestController
-@RequestMapping(value = "/api/member")
-public class MemberController {
-
- @Resource
- MemberService memberService;
-
- /**
- * 获取当前版本号
- */
- @ApiOperation(value="APP端获取当前版本号", notes="获取当前版本号")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = AppVersionListVo.class)})
- @GetMapping(value = "/getAppVersionInfo")
- public Result getAppVersionInfo() {
- return memberService.getAppVersionInfo();
- }
-
-
- /**
- * 获取当前版本号
- */
- @ApiOperation(value="PC端获取当前版本号", notes="获取当前版本号")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = AppVersionListVo.class)})
- @GetMapping(value = "/getPcVersionInfo")
- public Result getPcVersionInfo() {
- return memberService.getPcVersionInfo();
- }
-
-
- /**
- * 获取我的信息
- * @return
- */
- @ApiOperation(value="获取我的信息", notes="获取我的信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberInfoVo.class)})
- @GetMapping(value = "/getMemberInfo")
- public Result getMemberInfo() {
- return memberService.getMemberInfo();
- }
-
- /**
- * 忘记密码
- * @return
- */
- @ApiOperation(value=" 忘记密码", notes=" 忘记密码")
- @PostMapping(value="/memberForgetPwd")
- public Result memberForgetPwd(@RequestBody @Valid MemberForgetPwdDto memberForgetPwdDto) {
- return memberService.memberForgetPwd(memberForgetPwdDto);
- }
-
- /**
- * 验证账户是否存在
- * @return
- */
- @ApiOperation(value="验证账户是否存在", notes="验证账户是否存在")
- @ApiImplicitParams({
- @ApiImplicitParam(name = "account", value = "账号", required = true, dataType = "String", paramType="query"),
- @ApiImplicitParam(name = "type", value = "类型 1:手机号 2:邮箱", required = true, dataType = "int", paramType="query")
- })
- @GetMapping(value = "/getMemberAccountInfo")
- public Result getMemberAccountInfo(String account,int type) {
- return memberService.getMemberAccountInfo(account,type);
- }
-
- /**
- * 修改密码
- * @return
- */
- @ApiOperation(value="修改密码", notes="修改密码")
- @PostMapping(value="/memberUpdatePwd")
- public Result memberUpdatePwd(@RequestBody @Valid MemberUpdatePwdDto memberUpdatePwdDto) {
- //System.out.println("修改密码:");
- return memberService.memberUpdatePwd(memberUpdatePwdDto);
- }
-
- /**
- * 修改资金密码时效性
- * @return
- */
- @ApiOperation(value="修改资金密码时效性", notes="修改资金密码时效性")
- @PostMapping(value="/memberUpdateTradersPwdTime")
- public Result memberUpdateTradersPwdTime(@RequestBody @Valid MemberUpdateTradersPwdTimeDto memberUpdateTradersPwdTimeDto) {
- //System.out.println("修改密码:");
- return memberService.memberUpdateTradersPwdTime(memberUpdateTradersPwdTimeDto);
- }
-
- /**
- * 获取实名认证信息
- * @return
- */
- @ApiOperation(value = "获取实名认证信息", notes = "获取实名认证信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberAuthenticationInfoVo.class)})
- @GetMapping(value = "/memberAuthenticationInfo")
- public Result memberAuthenticationInfo() {
- return memberService.memberAuthenticationInfo();
- }
-
- /**
- * 实名认证
- * @return
- */
- @ApiOperation(value="实名认证", notes="实名认证")
- @PostMapping(value="/memberAuthentication")
- public Result memberAuthentication(@RequestBody @Valid MemberAuthenticationDto memberAuthenticationDto) {
- return memberService.memberAuthentication(memberAuthenticationDto);
- }
-
- /**
- * 修改资金密码
- * @return
- */
- @ApiOperation(value="修改资金密码", notes="修改资金密码")
- @PostMapping(value="/memberUpdateTradePwd")
- public Result memberUpdateTradePwd(@RequestBody @Valid MemberUpdateTradePwdDto memberUpdateTradePwdDto) {
- return memberService.memberUpdateTradePwd(memberUpdateTradePwdDto);
- }
-
- /**
- * 用户退出登录
- * @return
- */
- @ApiOperation(value="用户退出登录", notes="用户退出登录")
- @GetMapping(value = "/memberLogout")
- public Result memberLogout() {
- return memberService.memberLogout();
- }
-
- /**
- * 设置交易密码
- * @param code
- * @param password
- * @param token
- * @return
- */
- @ApiOperation(value="设置交易密码", notes="设置交易密码")
- @PostMapping(value="/memberTradersPwd")
- public Result memberTradersPwd(@RequestBody @Valid MemberForgetPwdDto memberForgetPwdDto) {
- return memberService.memberTradersPwd(memberForgetPwdDto);
- }
-
- /**
- * 收款方式
- * @return
- */
- @ApiOperation(value="新增收款方式", notes="新增收款方式")
- @PostMapping(value="/memberAddPaymethod")
- public Result memberAddPaymethod(@RequestBody @Valid MemberPaymethodDto memberPaymethodDto) {
- return memberService.memberAddPaymethod(memberPaymethodDto);
- }
-
- /**
- * 收款方式
- * @return
- */
- @ApiOperation(value="删除收款方式", notes="删除收款方式")
- @PostMapping(value="/memberDelPaymethod")
- public Result memberDelPaymethod(@RequestBody @Valid MemberDelPaymethodDto memberDelPaymethodDto) {
- return memberService.memberDelPaymethod(memberDelPaymethodDto);
- }
-
- /**
- * 收款方式
- * @return
- */
- @ApiOperation(value="一个收款方式的详情", notes="一个收款方式的详情")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberPaymethodDetailVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "long", paramType="query")
- })
- @GetMapping(value = "/memberPaymethodDetail")
- public Result memberPaymethodDetail(long id) {
- return memberService.memberPaymethodDetail(id);
- }
-
- /**
- * 收款方式
- * @return
- */
- @ApiOperation(value="收款方式的列表", notes="收款方式的列表")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberPaymethodDetailListVo.class)})
- @GetMapping(value = "/memberPaymethodDetailList")
- public Result memberPaymethodDetailList() {
- return memberService.memberPaymethodDetailList();
- }
-
- /**
- * 绑定手机号
- * @return
- */
- @ApiOperation(value="绑定手机号", notes="绑定手机号")
- @PostMapping(value="/memberBindPhone")
- public Result memberBindPhone(@RequestBody @Valid MemberBindPhoneDto memberBindPhoneDto) {
- return memberService.memberBindPhone(memberBindPhoneDto);
- }
-
- /**
- * 绑定邮箱
- * @return
- */
- @ApiOperation(value="绑定邮箱", notes="绑定邮箱")
- @PostMapping(value="/memberBindEmail")
- public Result memberBindEmail(@RequestBody @Valid MemberBindEmailDto memberBindEmailDto) {
- return memberService.memberBindEmail(memberBindEmailDto);
- }
-
- /**
- * 获取币种地址
- * @return
- */
- @ApiOperation(value = "获取币种地址数量", notes = "获取币种地址数量")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberCoinAddressCountListVo.class)})
- @GetMapping(value = "/memberCoinAddressCount")
- public Result memberCoinAddressCount() {
- return memberService.memberCoinAddressCount();
- }
-
- /**
- * 获取提币地址
- * @return
- */
- @ApiOperation(value = "获取提币地址列表", notes = "获取提币地址列表")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberCoinAddressListVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query")
- })
- @GetMapping(value = "/memberCoinAddressList")
- public Result memberCoinAddressList(String symbol) {
- return memberService.memberCoinAddressList(symbol);
- }
-
- /**
- * 添加提币地址
- * @return
- */
- @ApiOperation(value = "添加提币地址", notes = "添加提币地址")
- @PostMapping(value = "/memberAddCoinAddress")
- public Result memberAddCoinAddress(@RequestBody @Valid MemberAddCoinAddressDto memberAddCoinAddressDto) {
- return memberService.memberAddCoinAddress(memberAddCoinAddressDto);
- }
-
- /**
- * 删除提币地址
- * @return
- */
- @ApiOperation(value="删除提币地址", notes="删除提币地址")
- @PostMapping(value="/memberDelCoinAddress")
- public Result memberDelCoinAddress(@RequestBody @Valid MemberDelCoinAddressDto memberDelCoinAddressDto) {
- return memberService.memberDelCoinAddress(memberDelCoinAddressDto);
- }
-
- /**
- * 获取发送验证码途径
- * @return
- */
- @ApiOperation(value = "获取发送验证码途径", notes = "获取发送验证码途径")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberSendCodeWayVo.class)})
- @GetMapping(value = "/memberSendCodeWay")
- public Result memberSendCodeWay() {
- return memberService.memberSendCodeWay();
- }
-
- /**
- * 获取个人中心信息
- * @return
- */
- @ApiOperation(value = "获取个人中心信息", notes = "获取个人中心信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberPersonCenterInfoVo.class)})
- @GetMapping(value = "/memberPersonCenterInfo")
- public Result memberPersonCenterInfo() {
- return memberService.memberPersonCenterInfo();
- }
-
- /**
- * 提币币种信息
- * @return
- */
- @ApiOperation(value = "获取提币币种信息", notes = "获取提币币种信息")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberCoinInfoListVo.class)})
- @GetMapping(value = "/memberCoinInfoList")
- public Result memberCoinInfoList() {
- return memberService.memberCoinInfoList();
- }
-
- /**
- * 提币币种可用资金
- * @param token
- * @param coinVo
- * @return
- */
- @ApiOperation(value = "提币币种可用资金", notes = "提币币种可用资金")
- @ApiResponses({@ApiResponse( code = 200, message = "success", response = MemberAvivableCoinInfoVo.class)})
- @ApiImplicitParams({
- @ApiImplicitParam(name = "symbol", value = "币种", required = true, dataType = "String", paramType="query")
- })
- @GetMapping(value = "/memberAvivableCoinInfo")
- public Result memberAvivableCoinInfo(String symbol) {
- return memberService.memberAvivableCoinInfo(symbol);
- }
-
- /**
- * 提币申请
- * @param token
- * @param coinVo
- * @return
- */
- @ApiOperation(value="提交提币申请", notes="提交提币申请")
- @PostMapping(value="/memberSubmitCoinApply")
- public Result memberSubmitCoinApply(@RequestBody @Valid MemberSubmitCoinApplyDto memberSubmitCoinApplyDto) {
- return memberService.memberSubmitCoinApply(memberSubmitCoinApplyDto);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/AgentReturnDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/AgentReturnDao.java
deleted file mode 100644
index d20792d..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/AgentReturnDao.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.AgentReturnEntity;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface AgentReturnDao extends BaseMapper<AgentReturnEntity> {
-
- List<AgentReturnEntity> selectAllNeedMoneyReturn();
-
- int updateAgentReturnStatusByRefererId(@Param("isReturn") int isReturn, @Param("refererId") Long refererId);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/AppVersionDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/AppVersionDao.java
deleted file mode 100644
index d487e27..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/AppVersionDao.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.AppVersionEntity;
-
-public interface AppVersionDao extends BaseMapper<AppVersionEntity> {
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberAuthenticationDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberAuthenticationDao.java
deleted file mode 100644
index 51e3adb..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberAuthenticationDao.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberAuthenticationEntity;
-
-public interface MemberAuthenticationDao extends BaseMapper<MemberAuthenticationEntity> {
-
- int findMemberbyIdCardNoCount(String idCardNo);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinAddressDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinAddressDao.java
deleted file mode 100644
index b9fea92..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinAddressDao.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberCoinAddressEntity;
-
-public interface MemberCoinAddressDao extends BaseMapper<MemberCoinAddressEntity> {
-
- MemberCoinAddressEntity selectAddressByMemberIdAndSymbol(Long memberId, String symbol);
-
- MemberCoinAddressEntity selectBlockAddressWithTag(@Param("memberId") Long memberId, @Param("symbol") String symbol, @Param("tag") String tag);
-
- MemberCoinAddressEntity selectBlockAddress(@Param("memberId") Long memberId, @Param("symbol") String symbol);
-
- List<MemberCoinAddressEntity> selectCoinAddressListByMap(@Param("symbol") String symbol, @Param("memberId") Long memberId);
-
- List<MemberCoinAddressEntity> selectAllBlockAddressBySymbolAndTag(@Param("symbol") String symbol, @Param("tag") String tag);
-
- List<MemberCoinAddressEntity> selectAllBlockAddressBySymbol(@Param("symbol") String symbol);
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinChargeDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinChargeDao.java
deleted file mode 100644
index c35bdb0..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinChargeDao.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberCoinChargeEntity;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-public interface MemberCoinChargeDao extends BaseMapper<MemberCoinChargeEntity> {
-
- public MemberCoinChargeEntity selectNewestChargeRecord(@Param("memberId") Long memberId, @Param("symbol") String symbol, @Param("tag") String tag);
-
- List<MemberCoinChargeEntity> selectAllBySymbolAndTag(@Param("symbol") String symbol, @Param("tag") String tag, @Param("status") Integer status);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinWithdrawDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinWithdrawDao.java
deleted file mode 100644
index 75ce0f4..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberCoinWithdrawDao.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberCoinWithdrawEntity;
-
-public interface MemberCoinWithdrawDao extends BaseMapper<MemberCoinWithdrawEntity> {
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberDao.java
deleted file mode 100644
index b7e285a..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberDao.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-import com.xcong.excoin.modules.member.parameter.vo.NeedMoneyMemberVo;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author wzy
- */
-public interface MemberDao extends BaseMapper<MemberEntity> {
-
- public MemberEntity selectMemberInfoByAccount(@Param("account") String account);
-
- public MemberEntity selectMemberInfoByInviteId(@Param("inviteId") String inviteId);
-
- public NeedMoneyMemberVo selectFriendRelationUserByMemberId(@Param("memberId") Long memberId);
-
- public List<NeedMoneyMemberVo> selectAllNeedMoneyMember(@Param("list") List<String> list);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberLevelRateDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberLevelRateDao.java
deleted file mode 100644
index bfea23f..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberLevelRateDao.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberLevelRateEntity;
-import org.apache.ibatis.annotations.Param;
-
-public interface MemberLevelRateDao extends BaseMapper<MemberLevelRateEntity> {
-
- public MemberLevelRateEntity selectLeverRateByMemberIdAndSymbol(@Param("memberId") Long memberId, @Param("symbol") String symbol);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberPaymentMethodDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberPaymentMethodDao.java
deleted file mode 100644
index 1aaebf2..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberPaymentMethodDao.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import java.util.List;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberPaymentMethodEntity;
-
-public interface MemberPaymentMethodDao extends BaseMapper<MemberPaymentMethodEntity> {
-
- public List<MemberPaymentMethodEntity> selectByMemberId(Long memberId);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberSettingDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberSettingDao.java
deleted file mode 100644
index 620a813..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberSettingDao.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberSettingEntity;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-08-13
- **/
-public interface MemberSettingDao extends BaseMapper<MemberSettingEntity> {
-
- public MemberSettingEntity selectMemberSettingByMemberId(@Param("memberId") Long memberId);
-
- public int batchInsert(@Param("list") List<MemberSettingEntity> list);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletAgentDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletAgentDao.java
deleted file mode 100644
index 595a570..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletAgentDao.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberWalletAgentEntity;
-
-public interface MemberWalletAgentDao extends BaseMapper<MemberWalletAgentEntity> {
-
- MemberWalletAgentEntity selectWalletAgentBymIdAndCode(@Param("memberId")Long memberId,@Param("walletCode")String walletCode);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletCoinDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletCoinDao.java
deleted file mode 100644
index 66a50dc..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletCoinDao.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
-
-/**
- * @author wzy
- */
-public interface MemberWalletCoinDao extends BaseMapper<MemberWalletCoinEntity> {
-
- List<MemberWalletCoinEntity> selectMemberWalletCoinsByMemberId(Long memberId);
-
- MemberWalletCoinEntity selectWalletCoinBymIdAndCode(@Param("memberId") Long memberId, @Param("walletCode") String walletCode);
-
- int updateFrozenBalance(@Param("memberId") Long memberId, @Param("id") Long id, @Param("amount") BigDecimal amount);
-
- int subFrozenBalance(@Param("memberId") Long memberId, @Param("id") Long id, @Param("amount") BigDecimal amount);
-
- int updateBlockBalance(@Param("id") Long id, @Param("availableBalance") BigDecimal availableBalance, @Param("earlyBalance") BigDecimal earlyBalance, @Param("blockNumber") Integer blockNumber);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletContractDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletContractDao.java
deleted file mode 100644
index e12db7e..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletContractDao.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-
-import java.math.BigDecimal;
-
-public interface MemberWalletContractDao extends BaseMapper<MemberWalletContractEntity> {
-
- MemberWalletContractEntity findWalletContractByMemberIdAndSymbol(@Param("memberId")Long memberId, @Param("symbol")String symbol);
-
- /**
- * 增减合约钱包(负数为减)
- * @param availableBalance
- * @param totalBalance
- * @param frozenBalance
- * @param id
- */
- void increaseWalletContractBalanceById(@Param("availableBalance") BigDecimal availableBalance,@Param("totalBalance") BigDecimal totalBalance,@Param("frozenBalance") BigDecimal frozenBalance,@Param("id") Long id);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletContractSimulateDao.java b/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletContractSimulateDao.java
deleted file mode 100644
index ca43023..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletContractSimulateDao.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xcong.excoin.modules.member.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractSimulateEntity;
-
-/**
- * @author helius
- */
-public interface MemberWalletContractSimulateDao extends BaseMapper<MemberWalletContractSimulateEntity> {
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/AgentReturnEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/AgentReturnEntity.java
deleted file mode 100644
index 4cefe1a..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/AgentReturnEntity.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-05-31
- **/
-@Data
-@TableName("agent_return")
-public class AgentReturnEntity extends BaseEntity {
-
- /**
- * 订单类型 开仓
- */
- public static final int ORDER_TYPE_OPEN = 1;
-
- /**
- * 订单类型 平仓
- */
- public static final int ORDER_TYPE_CLOSE = 2;
-
- /**
- * 订单类型 持仓
- */
- public static final int ORDER_TYPE_HOLD = 3;
-
- /**
- * 是否已返佣 0-否
- */
- public static final int IS_RETURN_N = 0;
-
- /**
- * 是否已返佣 1-是
- */
- public static final int IS_RETURN_Y = 1;
-
- private Long memberId;
-
- private Long orderId;
-
- private String orderNo;
-
- private int orderType;
-
- private BigDecimal closingFeeAmount;
-
- private BigDecimal holdingFeeAmount;
-
- private BigDecimal openingFeeAmount;
-
- private BigDecimal returnAmount;
-
- private Long refererId;
-
- private String inviteId;
-
- private BigDecimal returnRatio;
-
- private BigDecimal childReturnRatio;
-
- /**
- * 0-否1-是
- */
- private int isReturn;
-
- private String returnSymbol;
-
- private int closingType;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/AppVersionEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/AppVersionEntity.java
deleted file mode 100644
index 2261fdc..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/AppVersionEntity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import java.io.Serializable;
-import java.util.Date;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-import lombok.Data;
-/**
- * 版本表
- *
- **/
-@Data
-@TableName("app_version")
-public class AppVersionEntity implements Serializable {
- /**
- * 账号状态 - 禁用
- */
- public static final Integer type_and = 1;
-
- /**
- * 账号状态 - 启用
- */
- public static final Integer type_app = 2;
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date createtime;
-
- private String version;
- private String content;
- private String address;
- private Integer type;
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberAuthenticationEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberAuthenticationEntity.java
deleted file mode 100644
index 619df68..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberAuthenticationEntity.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-/**
- * 用户实名认证信息实体
- *
- * @author wzy
- * @date 2020-05-18
- **/
-@Data
-@TableName("member_authentication")
-public class MemberAuthenticationEntity extends BaseEntity {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * 用户ID
- */
- private Long memberId;
-
- /**
- * 真实姓名
- */
- private String realName;
-
- /**
- * 姓
- */
- private String firstName;
-
- /**
- * 名
- */
- private String secondName;
-
- /**
- * 国家
- */
- private String nation;
-
- /**
- * 身份证号
- */
- private String idcardNo;
-
- /**
- * 证件类型
- */
- private String type;
-
- /**
- * 身份证正面
- */
- private String idcardImageFront;
-
- /**
- * 身份证背面
- */
- private String idcardImageBack;
-
- /**
- * 手持身份证
- */
- private String idcardImageInHand;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinAddressEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinAddressEntity.java
deleted file mode 100644
index 853703c..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinAddressEntity.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-/**
- * 会员币地址
- * @author Administrator
- *
- */
-@Data
-@TableName("member_coin_address")
-public class MemberCoinAddressEntity extends BaseEntity {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- /**
- * 会员ID
- */
- private Long memberId;
- /**
- * 地址
- */
- private String address;
- /**
- * 私钥
- */
- private String privateKey;
- /**
- * 币种
- */
- private String symbol;
- /**
- * 是否是本平台地址1:是 0:否
- */
- private String isBiyict;
- public static final String IS_BIYICT_YES = "1";
- public static final String IS_BIYICT_NO = "2";
- /**
- *
- */
- private String label;
- /**
- *
- */
- private String tag;
- /**
- * 币种ID
- */
- private Long symbolscoinId;
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinChargeEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinChargeEntity.java
deleted file mode 100644
index 8171578..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinChargeEntity.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-07-02
- **/
-@Data
-@TableName("member_coin_charge")
-public class MemberCoinChargeEntity extends BaseEntity {
-
- private Long memberId;
-
- private String certificate;
-
- private BigDecimal amount;
-
- private BigDecimal lastAmount;
-
- private int status;
-
- private String symbol;
-
- private String address;
-
- private String tag;
-
- private String hash;
-
- private String orderCode;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinWithdrawEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinWithdrawEntity.java
deleted file mode 100644
index cea3765..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberCoinWithdrawEntity.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-
-/**
- * 会员提币表
- */
-@Data
-@TableName("member_coin_withdraw")
-public class MemberCoinWithdrawEntity extends BaseEntity{
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- /**
- * 会员ID
- */
- private Long memberId;
- /**
- * 地址
- */
- private String address;
- /**
- * 提币数量
- */
- private BigDecimal amount;
- /**
- * 手续费
- */
- private BigDecimal feeAmount;
- /**
- * 币种
- */
- private String symbol;
- /**
- * 状态
- */
- private int status;
- public static final int STATUS_DOING = 1;
- /**
- * 是否内部转账 Y-是N-不是
- */
- private String isInside;
- public static final String ISINSIDE_YES = "Y";
- public static final String ISINSIDE_NO = "N";
-
- private String label;
-
- private String tag;
-
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java
deleted file mode 100644
index aaa7e5e..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-import java.math.BigDecimal;
-
-/**
- * 会员信息实体
- *
- * @author wzy
- * @date 2020-05-12
- **/
-@Data
-@TableName("member")
-public class MemberEntity extends BaseEntity {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * 账号状态 - 禁用
- */
- public static final Integer ACCOUNT_STATUS_DISABLED = 0;
-
- /**
- * 账号状态 - 启用
- */
- public static final Integer ACCOUNT_STATUS_ENABLE = 1;
-
- /**
- * 账号代理级别
- */
- public static final Integer ACCOUNT_AGENT_LEVEL = 6;
-
- /**
- * 账号类型 手机
- */
- public static final Integer ACCOUNT_TYPE_PHONE = 1;
-
- /**
- * 账号类型 邮箱
- */
- public static final Integer ACCOUNT_TYPE_EMAIL = 2;
-
- /**
- * 正常账号
- */
- public static final Integer ACCOUNT_TYPE_NORMAL = 1;
- /**
- * 测试账号
- */
- public static final Integer ACCOUNT_TYPE_TEST = 2;
-
- /**
- * 实名认证 审核通过
- */
- public static final Integer CERTIFY_STATUS_Y = 2;
- /**
- * 实名认证 审核不通过
- */
- public static final Integer CERTIFY_STATUS_N = 0;
- /**
- * 实名认证 审核中
- */
- public static final Integer CERTIFY_STATUS_ING = 1;
- /**
- * 实名认证 未提交
- */
- public static final Integer CERTIFY_STATUS_UN_SUBMIT = 3;
-
- public static final int IS_PROFIT_Y = 1;
-
- public static final int IS_PROFIT_N = 0;
-
- /**
- * 手机号(包含国际手机号)
- */
- private String phone;
-
- /**
- * 邮箱
- */
- private String email;
-
- /**
- * 登陆密码
- */
- private String password;
-
- /**
- * 交易密码
- */
- private String tradePassword;
-
- /**
- * 交易密码时效性设置
- */
- private Integer tradeAgingSetting;
-
- /**
- * 邀请码
- */
- private String inviteId;
-
- /**
- * 账号状态 0-禁用 1-启用
- */
- private int accountStatus;
-
- /**
- * 上级推荐人id
- */
- private String refererId;
-
- /**
- * 上级推荐人ID链
- */
- private String refererIds;
-
- /**
- * 账号类型 1-正常账号 2-测试账号
- */
- private Integer accountType;
-
- /**
- * 代理级别
- */
- private Integer agentLevel;
-
- /**
- * 实名认证状态 0-审核未通过 1-审核通过 2-等待审核
- */
- private Integer certifyStatus;
-
- /**
- * 身份证号
- */
- private String idcardNo;
-
- /**
- * 是否设置盈亏难度系数 0-否1-是
- */
- private Integer isProfit;
-
- /**
- * 是否设置预估强平价系数 0-否1-是
- */
- private Integer isForce;
-
- /**
- * 滑点
- */
- private BigDecimal spread;
-
- /**
- * 平仓点数
- */
- private BigDecimal closingSpread;
-
- /**
- * 强平系数
- */
- private BigDecimal forceParam;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberLevelRateEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberLevelRateEntity.java
deleted file mode 100644
index ef68aab..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberLevelRateEntity.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-/**
- * 用户杠杆设置表
- *
- * @Author wzy
- * @Date 2020/5/18
- **/
-@Data
-@TableName("member_level_rate")
-public class MemberLevelRateEntity extends BaseEntity {
-
- /**
- * 会员ID
- */
- private Long memberId;
-
- /**
- * 多头杠杆
- */
- private int levelRateUp = 100;
-
- /**
- * 空头杠杆
- */
- private int levelRateDown = 100;
-
- /**
- * 币种
- */
- private String symbol;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberPaymentMethodEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberPaymentMethodEntity.java
deleted file mode 100644
index be0e903..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberPaymentMethodEntity.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-
-/**
- * 会员收款方式
- */
-@Data
-@TableName("member_payment_method")
-public class MemberPaymentMethodEntity extends BaseEntity{
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * 用户Id
- */
- private Long memberId;
- /**
- * 姓名
- */
- private String name;
- /**
- * 账号
- */
- private String account;
- /**
- * 收款二维码
- */
- private String paymentQrcode;
- /**
- * 银行
- */
- private String bank;
- /**
- * 支行
- */
- private String subBank;
- /**
- * 类型 1-支付宝2-微信3-银行卡
- */
- private String paymentType;
- public static final Integer PAYMENTTYPE_ALIPAY = 1;
- public static final Integer PAYMENTTYPE_WECHAT = 2;
- public static final Integer PAYMENTTYPE_CARD = 3;
-
- /**
- * 默认收款方式
- */
- private String isDefualt;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberSelectSymbolsEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberSelectSymbolsEntity.java
deleted file mode 100644
index 8b5b5fd..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberSelectSymbolsEntity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-
-/**
- * 会员自选币种
- */
-@Data
-@TableName("member_select_symbols")
-public class MemberSelectSymbolsEntity extends BaseEntity{
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- /**
- * 会员ID
- */
- private long memberId;
- /**
- * 币种
- */
- private String symbol;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberSettingEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberSettingEntity.java
deleted file mode 100644
index 36ea5a7..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberSettingEntity.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-08-13
- **/
-@Data
-@TableName("member_setting")
-public class MemberSettingEntity extends BaseEntity {
-
- private Long memberId;
-
- /**
- * 滑点
- */
- private BigDecimal spread;
-
- /**
- * 平仓点数
- */
- private BigDecimal closingSpread;
-
- /**
- * 强平系数
- */
- private BigDecimal forceParam;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletAgentEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletAgentEntity.java
deleted file mode 100644
index bb067cf..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletAgentEntity.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * 代理用户钱包
- *
- * @author wzy
- * @date 2020-05-18
- **/
-@Data
-@TableName("member_wallet_agent")
-public class MemberWalletAgentEntity extends BaseEntity {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * 用户Id
- */
- private Long memberId;
-
- /**
- * 可用余额
- */
- private BigDecimal availableBalance = AppContants.INIT_MONEY;
-
- /**
- * 总金额
- */
- private BigDecimal totalBalance = AppContants.INIT_MONEY;
-
- /**
- * 冻结金额
- */
- private BigDecimal frozenBalance = AppContants.INIT_MONEY;
-
- /**
- * 借入资产金额
- */
- private BigDecimal borrowedFund = AppContants.INIT_MONEY;
-
- /**
- * 钱包标识
- */
- private String walletCode;
-
- /**
- * 钱包地址
- */
- private String walletAddress;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletCoinEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletCoinEntity.java
deleted file mode 100644
index f2bd58c..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletCoinEntity.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-05-18
- **/
-@Data
-@TableName("member_wallet_coin")
-public class MemberWalletCoinEntity extends BaseEntity {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 用户Id
- */
- private Long memberId;
-
- /**
- * 可用余额
- */
- private BigDecimal availableBalance;
-
- /**
- * 总金额
- */
- private BigDecimal totalBalance;
-
- /**
- * 冻结金额
- */
- private BigDecimal frozenBalance;
-
- /**
- * 借入资产金额
- */
- private BigDecimal borrowedFund;
-
- /**
- * 钱包标识
- */
- private String walletCode;
-
- /**
- * 钱包地址
- */
- private String walletAddress;
-
- /**
- * 上次余额
- */
- private BigDecimal earlyBalance;
-
- /**
- * 区块编号
- */
- private int blockNumber;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletContractEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletContractEntity.java
deleted file mode 100644
index 91cd275..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletContractEntity.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-05-18
- **/
-@Data
-@TableName("member_wallet_contract")
-public class MemberWalletContractEntity extends BaseEntity {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- private Long memberId;
-
- private BigDecimal availableBalance;
-
- private BigDecimal totalBalance;
-
- private BigDecimal frozenBalance;
-
- private BigDecimal borrowedFund;
-
- private String walletCode;
-
- private String walletAddress;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletContractSimulateEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletContractSimulateEntity.java
deleted file mode 100644
index 6554e6e..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/entity/MemberWalletContractSimulateEntity.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.xcong.excoin.modules.member.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-05-18
- **/
-@Data
-@TableName("member_wallet_contract_simulate")
-public class MemberWalletContractSimulateEntity extends BaseEntity {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- private Long memberId;
-
- private BigDecimal availableBalance;
-
- private BigDecimal totalBalance;
-
- private BigDecimal frozenBalance;
-
- private BigDecimal borrowedFund;
-
- private String walletCode;
-
- private String walletAddress;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberAddCoinAddressDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberAddCoinAddressDto.java
deleted file mode 100644
index 4bf9314..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberAddCoinAddressDto.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberAddCoinAddressDto", description = "增加提币地址参数接收类")
-public class MemberAddCoinAddressDto {
-
- @NotNull(message = "币种ID不能为空")
- @ApiModelProperty(value = "币种ID")
- private Long symbolscoinId;
- /**
- * 地址
- */
- @NotNull(message = "地址不能为空")
- @ApiModelProperty(value = "地址")
- private String address;
- /**
- * 是否是本平台地址1:是 0:否
- */
- @NotNull(message = "是否是本平台地址不能为空")
- @ApiModelProperty(value = "是否是本平台地址1:是 0:否")
- private String isBiyict;
- /**
- * 备注
- */
- @ApiModelProperty(value = "备注")
- private String remark;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberAuthenticationDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberAuthenticationDto.java
deleted file mode 100644
index 60d7bb2..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberAuthenticationDto.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberAuthenticationDto", description = "实名认证参数接收类")
-public class MemberAuthenticationDto {
-
- @NotNull(message = "姓不能为空")
- @ApiModelProperty(value = "姓", example = "姓")
- private String firstName;
-
- @NotNull(message = "名不能为空")
- @ApiModelProperty(value = "名", example = "名")
- private String secondName;
-
- @NotNull(message = "真实姓名不能为空")
- @ApiModelProperty(value = "真实姓名", example = "姓名")
- private String realName;
-
- @NotNull(message = "身份证卡号不能为空")
- @ApiModelProperty(value = "身份证卡号", example = "123456789")
- private String idCardNo;
-
- @NotNull(message = "身份证正面不能为空")
- @ApiModelProperty(value = "身份证正面", example = "身份证正面")
- private String idCardFront;
-
- @NotNull(message = "身份证反面不能为空")
- @ApiModelProperty(value = "身份证反面", example = "身份证反面")
- private String idCardReverse;
-
- @NotNull(message = "手持身份证不能为空")
- @ApiModelProperty(value = "手持身份证", example = "手持身份证")
- private String idCardImage;
-
- @NotNull(message = "国家不能为空")
- @ApiModelProperty(value = "国家", example = "国家")
- private String nation;
-
- @NotNull(message = "类型不能为空")
- @ApiModelProperty(value = "类型1:身份证2:护照编号", example = "1")
- private String type;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberBindEmailDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberBindEmailDto.java
deleted file mode 100644
index 1a8f2cc..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberBindEmailDto.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberBindEmailDto", description = "绑定邮箱参数接收类")
-public class MemberBindEmailDto {
-
- @NotNull(message = "验证码不能为空")
- @ApiModelProperty(value = "验证码", example = "123456")
- private String code;
-
- @NotNull(message = "邮箱不能为空")
- @ApiModelProperty(value = "邮箱", example = "www.13412341234@134.com")
- private String email;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberBindPhoneDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberBindPhoneDto.java
deleted file mode 100644
index f7d6afc..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberBindPhoneDto.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberBindPhoneDto", description = "绑定手机号参数接收类")
-public class MemberBindPhoneDto {
-
- @NotNull(message = "验证码不能为空")
- @ApiModelProperty(value = "验证码", example = "123456")
- private String code;
-
- @NotNull(message = "电话号码不能为空")
- @ApiModelProperty(value = "电话号码", example = "13412341234")
- private String phone;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberDelCoinAddressDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberDelCoinAddressDto.java
deleted file mode 100644
index 0277ead..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberDelCoinAddressDto.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberDelCoinAddressDto", description = "删除提币地址参数接收类")
-public class MemberDelCoinAddressDto {
-
- @NotNull(message = "提币地址ID不能为空")
- @ApiModelProperty(value = "提币地址ID", example = "1")
- private Long id;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberDelPaymethodDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberDelPaymethodDto.java
deleted file mode 100644
index 1135c4a..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberDelPaymethodDto.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberDelPaymethodDto", description = "删除收款方式参数接收类")
-public class MemberDelPaymethodDto {
-
- @NotNull(message = "收款方式ID不能为空")
- @ApiModelProperty(value = "收款方式ID", example = "1")
- private Long id;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberForgetPwdDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberForgetPwdDto.java
deleted file mode 100644
index 9ff9a5d..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberForgetPwdDto.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberForgetPwdDto", description = "忘记密码参数接收类")
-public class MemberForgetPwdDto {
-
- @NotNull(message = "验证码不能为空")
- @ApiModelProperty(value = "验证码", example = "123456")
- private String code;
-
- @NotNull(message = "新密码不能为空")
- @ApiModelProperty(value = "新密码", example = "qq123456")
- private String password;
-
- @NotNull(message = "验证类型不能为空")
- @ApiModelProperty(value = "验证类型 1 手机号码 2 邮箱", example = "1")
- private int type;
-
- @NotNull(message = "验证账号不能为空")
- @ApiModelProperty(value = "验证账号", example = "13412341234")
- private String account;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberPaymethodDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberPaymethodDto.java
deleted file mode 100644
index fa2a3b2..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberPaymethodDto.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberPaymethodDto", description = "收款方式参数接收类")
-public class MemberPaymethodDto {
- /**
- * 姓名
- */
- @NotNull(message = "姓名不能为空")
- @ApiModelProperty(value = "姓名", example = "姓名")
- private String name;
- /**
- * 账号
- */
- @NotNull(message = "账号不能为空")
- @ApiModelProperty(value = "账号", example = "13412341234")
- private String account;
- /**
- * 收款二维码
- */
- @ApiModelProperty(value = "账号", example = "13412341234")
- private String paymentQrcode;
- /**
- * 银行
- */
- @ApiModelProperty(value = "银行", example = "银行")
- private String bank;
- /**
- * 支行
- */
- @ApiModelProperty(value = "支行", example = "支行")
- private String subBank;
- /**
- * 类型 1-支付宝2-微信3-银行卡
- */
- @NotNull(message = "类型不能为空")
- @ApiModelProperty(value = "类型 1-支付宝2-微信3-银行卡", example = "1")
- private String paymentType;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberSubmitCoinApplyDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberSubmitCoinApplyDto.java
deleted file mode 100644
index 5d4fa7b..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberSubmitCoinApplyDto.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import java.math.BigDecimal;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberSubmitCoinApplyDto", description = "提交提币申请参数接收类")
-public class MemberSubmitCoinApplyDto {
-
- @NotNull(message = "地址不能为空")
- @ApiModelProperty(value = "地址", example = "asfdsdafsdafdsaf1231232sdfsa")
- private String address;
-
- @NotNull(message = "币数量不能为空")
- @ApiModelProperty(value = "币数量", example = "10")
- private BigDecimal coinNumber;
-
- @NotNull(message = "手续费不能为空")
- @ApiModelProperty(value = "手续费", example = "10")
- private BigDecimal feeAmount;
-
- @NotNull(message = "交易密码不能为空")
- @ApiModelProperty(value = "交易密码", example = "123456")
- private String tradePassword;
-
- @NotNull(message = "验证码不能为空")
- @ApiModelProperty(value = "验证码", example = "123456")
- private String code;
-
- @NotNull(message = "验证方式不能为空")
- @ApiModelProperty(value = "验证方式", example = "13412341234")
- private String account;
-
- @NotNull(message = "币种不能为空")
- @ApiModelProperty(value = "币种", example = "BTC")
- private String symbol;
-
- @ApiModelProperty(value = "姓名", example = "姓名")
- private String lable;
-
- @ApiModelProperty(value = "姓名", example = "姓名")
- private String tag;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberTradersPwdDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberTradersPwdDto.java
deleted file mode 100644
index 884119f..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberTradersPwdDto.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberTradersPwdDto", description = "设置交易密码参数接收类")
-public class MemberTradersPwdDto {
-
- @NotNull(message = "验证码不能为空")
- @ApiModelProperty(value = "验证码", example = "123456")
- private String code;
-
- @NotNull(message = "新密码不能为空")
- @ApiModelProperty(value = "新密码", example = "qq123456")
- private String password;
-
- @NotNull(message = "验证类型不能为空")
- @ApiModelProperty(value = "验证类型 1 手机号码 2 邮箱", example = "1")
- private int type;
-
- @ApiModelProperty(value = "电话号码", example = "13412341234")
- private String phone;
-
- @ApiModelProperty(value = "邮箱", example = "www.13412341234@123.com")
- private String email;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdatePwdDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdatePwdDto.java
deleted file mode 100644
index 0e2b96c..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdatePwdDto.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberUpdatePwdDto", description = "修改密码参数接收类")
-public class MemberUpdatePwdDto {
-
- @NotNull(message = "验证码不能为空")
- @ApiModelProperty(value = "验证码", example = "123456")
- private String code;
-
- @NotNull(message = "新密码不能为空")
- @ApiModelProperty(value = "新密码", example = "qq123456")
- private String password;
-
- @NotNull(message = "验证类型不能为空")
- @ApiModelProperty(value = "验证类型 1 手机号码 2 邮箱", example = "1")
- private int type;
-
- @ApiModelProperty(value = "电话号码", example = "13412341234")
- private String phone;
-
- @ApiModelProperty(value = "邮箱", example = "www.13412341234@123.com")
- private String email;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdateTradePwdDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdateTradePwdDto.java
deleted file mode 100644
index 650b4d7..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdateTradePwdDto.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberUpdateTradePwdDto", description = "修改资金密码参数接收类")
-public class MemberUpdateTradePwdDto {
-
- @NotNull(message = "验证码不能为空")
- @ApiModelProperty(value = "验证码", example = "123456")
- private String code;
-
- @NotNull(message = "新密码不能为空")
- @ApiModelProperty(value = "新密码", example = "qq123456")
- private String password;
-
- @NotNull(message = "验证类型不能为空")
- @ApiModelProperty(value = "验证类型 1 手机号码 2 邮箱", example = "1")
- private int type;
-
- @NotNull(message = "验证账号不能为空")
- @ApiModelProperty(value = "验证账号", example = "13412341234")
- private String account;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdateTradersPwdTimeDto.java b/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdateTradersPwdTimeDto.java
deleted file mode 100644
index 09da5a6..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/dto/MemberUpdateTradersPwdTimeDto.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.dto;
-
-import javax.validation.constraints.NotNull;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberUpdateTradersPwdTimeDto", description = "修改资金密码时效性接收类")
-public class MemberUpdateTradersPwdTimeDto {
-
- @NotNull(message = "交易密码时效性设置不能为空")
- @ApiModelProperty(value = "交易密码时效性设置1:一直需要输入密码 2不需要输入密码", example = "1")
- private Integer tradeAgingSetting;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/AppVersionListVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/AppVersionListVo.java
deleted file mode 100644
index 2d11e03..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/AppVersionListVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "AppVersionListVo", description = "版本信息列表")
-public class AppVersionListVo {
-
- @ApiModelProperty(value = "版本信息")
- private List<AppVersionVo> appVersionVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/AppVersionVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/AppVersionVo.java
deleted file mode 100644
index e3da351..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/AppVersionVo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "AppVersionVo", description = "版本号信息")
-public class AppVersionVo {
-
- @ApiModelProperty(value = "版本号")
- private String version;
-
- @ApiModelProperty(value = "下载地址")
- private String address;
-
- @ApiModelProperty(value = "类型:1安卓,2苹果")
- private Integer type;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberAuthenticationInfoVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberAuthenticationInfoVo.java
deleted file mode 100644
index c680aa3..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberAuthenticationInfoVo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberAuthenticationInfoVo", description = "实名认证信息")
-public class MemberAuthenticationInfoVo {
-
- @ApiModelProperty(value = "实名认证状态 0-审核未通过 1-审核中 2-审核通过")
- private Integer certifyStatus;
-
- @ApiModelProperty(value = "姓")
- private String firstName;
-
- @ApiModelProperty(value = "名")
- private String secondName;
-
- @ApiModelProperty(value = "身份证卡号")
- private String idCardNo;
-
- @ApiModelProperty(value = "证件类型")
- private String type;
-
- @ApiModelProperty(value = "国家")
- private String nation;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberAvivableCoinInfoVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberAvivableCoinInfoVo.java
deleted file mode 100644
index 7231563..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberAvivableCoinInfoVo.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import java.math.BigDecimal;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberAvivableCoinInfoVo", description = "提币币种可用资金信息")
-public class MemberAvivableCoinInfoVo {
-
- @ApiModelProperty(value = "可用余额")
- private BigDecimal availableBalance;
-
- @ApiModelProperty(value = "手续费")
- private BigDecimal fee;
-
- @ApiModelProperty(value = "USDT链名")
- private String lable;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressCountListVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressCountListVo.java
deleted file mode 100644
index 0ef11f8..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressCountListVo.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberCoinAddressCountListVo", description = "币种地址信息")
-public class MemberCoinAddressCountListVo {
-
-
- @ApiModelProperty(value = "币种地址")
- private List<MemberCoinAddressCountVo> memberCoinAddressCountVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressCountVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressCountVo.java
deleted file mode 100644
index 7d52ead..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressCountVo.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberCoinAddressCountVo", description = "币种地址数量信息")
-public class MemberCoinAddressCountVo {
-
- @ApiModelProperty(value = "ID")
- private Long id;
- /**
- * 币种
- */
- @ApiModelProperty(value = "币种")
- private String name;
- /**
- * 地址数量
- */
- @ApiModelProperty(value = "地址数量")
- private Integer count;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressListVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressListVo.java
deleted file mode 100644
index a35d316..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressListVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberCoinAddressListVo", description = "币种地址信息")
-public class MemberCoinAddressListVo {
-
- @ApiModelProperty(value = "币种地址")
- private List<MemberCoinAddressVo> memberCoinAddressVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressVo.java
deleted file mode 100644
index 5532f0b..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinAddressVo.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberCoinAddressVo", description = "地址信息")
-public class MemberCoinAddressVo {
-
- @ApiModelProperty(value = "ID")
- private Long id;
- /**
- * 会员ID
- */
- @ApiModelProperty(value = "会员ID")
- private Long memberId;
- /**
- * 地址
- */
- @ApiModelProperty(value = "地址")
- private String address;
- /**
- * 私钥
- */
- @ApiModelProperty(value = "私钥")
- private String privateKey;
- /**
- * 币种
- */
- @ApiModelProperty(value = "币种")
- private String symbol;
- /**
- * 是否是本平台地址1:是 0:否
- */
- @ApiModelProperty(value = "是否是本平台地址1:是 0:否")
- private String isBiyict;
-
- @ApiModelProperty(value = "备注")
- private String label;
-
- @ApiModelProperty(value = "ID")
- private Long symbolscoinId;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinInfoListVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinInfoListVo.java
deleted file mode 100644
index a5ac662..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinInfoListVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberCoinInfoListVo", description = "币种信息")
-public class MemberCoinInfoListVo {
-
- @ApiModelProperty(value = "币种名称")
- private List<MemberCoinInfoVo> memberCoinInfoVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinInfoVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinInfoVo.java
deleted file mode 100644
index 36d950e..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberCoinInfoVo.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberCoinInfoVo", description = "币种信息")
-public class MemberCoinInfoVo {
-
- @ApiModelProperty(value = "币种名称")
- private String name;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberInfoVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberInfoVo.java
deleted file mode 100644
index 6ab0a86..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberInfoVo.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberInfoVo", description = "个人信息")
-public class MemberInfoVo {
-
- /**
- * 手机号(包含国际手机号)
- */
- @ApiModelProperty(value = "手机号(包含国际手机号)")
- private String phone;
-
- /**
- * 邀请码
- */
- @ApiModelProperty(value = "邀请码")
- private String inviteId;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPaymethodDetailListVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPaymethodDetailListVo.java
deleted file mode 100644
index 19f1b91..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPaymethodDetailListVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import java.util.List;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberPaymethodDetailListVo", description = "收款方式列表")
-public class MemberPaymethodDetailListVo {
-
- @ApiModelProperty(value = "收款方式列表")
- private List<MemberPaymethodDetailVo> memberPaymethodDetailVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPaymethodDetailVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPaymethodDetailVo.java
deleted file mode 100644
index 72161ed..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPaymethodDetailVo.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberPaymethodDetailVo", description = "收款方式信息")
-public class MemberPaymethodDetailVo {
-
- /**
- * Id
- */
- @ApiModelProperty(value = "Id")
- private Long id;
- /**
- * 用户Id
- */
- @ApiModelProperty(value = "用户Id")
- private Long memberId;
- /**
- * 姓名
- */
- @ApiModelProperty(value = "姓名")
- private String name;
- /**
- * 账号
- */
- @ApiModelProperty(value = "账号")
- private String account;
- /**
- * 收款二维码
- */
- @ApiModelProperty(value = "收款二维码")
- private String paymentQrcode;
- /**
- * 银行
- */
- @ApiModelProperty(value = "银行")
- private String bank;
- /**
- * 支行
- */
- @ApiModelProperty(value = "支行")
- private String subBank;
- /**
- * 类型 1-支付宝2-微信3-银行卡
- */
- @ApiModelProperty(value = "类型 1-支付宝2-微信3-银行卡")
- private String paymentType;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPersonCenterInfoVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPersonCenterInfoVo.java
deleted file mode 100644
index 97576fc..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberPersonCenterInfoVo.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberPersonCenterInfoVo", description = "个人中心信息")
-public class MemberPersonCenterInfoVo {
-
- @ApiModelProperty(value = "手机号(包含国际手机号)1:有 0没有")
- private Integer phone;
-
- @ApiModelProperty(value = "邮箱1:有 0没有")
- private Integer email;
-
- @ApiModelProperty(value = "交易密码1:有 0没有")
- private Integer tradePassword;
-
- @ApiModelProperty(value = "收款方式1:有 0没有")
- private Integer memberPaymentMethod;
-
- @ApiModelProperty(value = "实名认证0:审核不通过 1:审核中 2: 审核通过 3:未提交")
- private Integer certifyStatus;
-
- @ApiModelProperty(value = "交易密码时效性设置1:一直需要输入密码 2不需要输入密码")
- private Integer tradeAgingSetting;
- /**
- * 一直需要输入密码
- */
- public static final int PWD_NEED_FORVER = 1;
-
- /**
- * 不需要输入密码
- */
- public static final int PWD_NEED_NO = 2;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberSendCodeWayVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberSendCodeWayVo.java
deleted file mode 100644
index 3f01954..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/MemberSendCodeWayVo.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "MemberSendCodeWayVo", description = "发送验证码途径信息")
-public class MemberSendCodeWayVo {
-
- /**
- * 手机号(包含国际手机号)
- */
- @ApiModelProperty(value = "手机号(包含国际手机号)")
- private String phone;
-
- /**
- * 邮箱
- */
- @ApiModelProperty(value = "邮箱")
- private String email;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/NeedMoneyMemberVo.java b/src/main/java/com/xcong/excoin/modules/member/parameter/vo/NeedMoneyMemberVo.java
deleted file mode 100644
index 0e06255..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/parameter/vo/NeedMoneyMemberVo.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xcong.excoin.modules.member.parameter.vo;
-
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * 返佣用户
- */
-@Data
-public class NeedMoneyMemberVo {
- private Long memberId;
- private String inviteId;
- private String referenceId;
- private BigDecimal returnRatio;
- private int levelId;
- private int feeIsSelf;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/service/MemberService.java b/src/main/java/com/xcong/excoin/modules/member/service/MemberService.java
deleted file mode 100644
index ae6e757..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/service/MemberService.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.xcong.excoin.modules.member.service;
-
-import javax.validation.Valid;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.dto.RegisterDto;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.parameter.dto.MemberAddCoinAddressDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberAuthenticationDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberBindEmailDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberBindPhoneDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberDelCoinAddressDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberDelPaymethodDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberForgetPwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberPaymethodDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberSubmitCoinApplyDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdatePwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdateTradePwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdateTradersPwdTimeDto;
-import com.xcong.excoin.modules.member.parameter.vo.NeedMoneyMemberVo;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author wzy
- */
-public interface MemberService extends IService<MemberEntity> {
-
- public Result register(RegisterDto registerDto);
-
- public Result getMemberInfo();
-
- public Result memberAuthentication(@Valid MemberAuthenticationDto memberAuthenticationDto);
-
- public Result memberForgetPwd(@Valid MemberForgetPwdDto memberForgetPwdDto);
-
- public Result memberUpdatePwd(@Valid MemberUpdatePwdDto memberUpdatePwdDto);
-
- public Result memberUpdateTradePwd(@Valid MemberUpdateTradePwdDto memberUpdateTradePwdDto);
-
- public Result memberLogout();
-
- public Result memberTradersPwd(@Valid MemberForgetPwdDto memberForgetPwdDto);
-
- public Result memberAddPaymethod(@Valid MemberPaymethodDto memberPaymethodDto);
-
- public Result memberDelPaymethod(@Valid MemberDelPaymethodDto memberDelPaymethodDto);
-
- public Result memberPaymethodDetail(long id);
-
- public Result memberPaymethodDetailList();
-
- public Result memberBindPhone(@Valid MemberBindPhoneDto memberBindPhoneDto);
-
- public Result memberBindEmail(@Valid MemberBindEmailDto memberBindEmailDto);
-
- public Result memberCoinAddressCount();
-
- public Result memberCoinAddressList(String symbol);
-
- public Result memberAddCoinAddress(@Valid MemberAddCoinAddressDto memberAddCoinAddressDto);
-
- public Result memberSendCodeWay();
-
- public Result memberDelCoinAddress(@Valid MemberDelCoinAddressDto memberDelCoinAddressDto);
-
- public Result memberAuthenticationInfo();
-
- public Result memberPersonCenterInfo();
-
- public Result memberCoinInfoList();
-
- public Result memberAvivableCoinInfo(String symbol);
-
- public NeedMoneyMemberVo selectFriendRelationUserByMemberId(Long memberId);
-
- public List<NeedMoneyMemberVo> selectAllNeedMoneyMember(List<String> list);
-
- public MemberEntity selectMemberInfoByInviteId(String inviteId);
-
- public Result memberUpdateTradersPwdTime(@Valid MemberUpdateTradersPwdTimeDto memberUpdateTradersPwdTimeDto);
-
- public Result memberSubmitCoinApply(@Valid MemberSubmitCoinApplyDto memberSubmitCoinApplyDto);
-
- public Result getMemberAccountInfo(String account,int type);
-
- public Result getAppVersionInfo();
-
- public Result getPcVersionInfo();
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/service/MemberWalletContractService.java b/src/main/java/com/xcong/excoin/modules/member/service/MemberWalletContractService.java
deleted file mode 100644
index 37840b3..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/service/MemberWalletContractService.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.member.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-import org.apache.ibatis.annotations.Param;
-
-import java.math.BigDecimal;
-
-public interface MemberWalletContractService extends IService<MemberWalletContractEntity> {
-
- MemberWalletContractEntity findWalletContractByMemberIdAndSymbol(Long memberId, String symbol);
-
- /**
- * 增减合约钱包(负数为减)
- * @param availableBalance
- * @param totalBalance
- * @param frozenBalance
- * @param id
- */
- void increaseWalletContractBalanceById(BigDecimal availableBalance, BigDecimal totalBalance, BigDecimal frozenBalance, Long id);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/member/service/impl/MemberServiceImpl.java b/src/main/java/com/xcong/excoin/modules/member/service/impl/MemberServiceImpl.java
deleted file mode 100644
index ec15f5e..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/service/impl/MemberServiceImpl.java
+++ /dev/null
@@ -1,1006 +0,0 @@
-package com.xcong.excoin.modules.member.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.SecureUtil;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.common.enumerates.SymbolEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.dto.RegisterDto;
-import com.xcong.excoin.common.system.service.CommonService;
-import com.xcong.excoin.modules.coin.dao.MemberAccountMoneyChangeDao;
-import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange;
-import com.xcong.excoin.modules.member.dao.*;
-import com.xcong.excoin.modules.member.entity.*;
-import com.xcong.excoin.modules.member.parameter.dto.MemberAddCoinAddressDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberAuthenticationDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberBindEmailDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberBindPhoneDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberDelCoinAddressDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberDelPaymethodDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberForgetPwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberPaymethodDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberSubmitCoinApplyDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdatePwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdateTradePwdDto;
-import com.xcong.excoin.modules.member.parameter.dto.MemberUpdateTradersPwdTimeDto;
-import com.xcong.excoin.modules.member.parameter.vo.*;
-import com.xcong.excoin.modules.member.service.MemberService;
-import com.xcong.excoin.modules.platform.dao.PlatformFeeSettingDao;
-import com.xcong.excoin.modules.platform.dao.PlatformSymbolsCoinDao;
-import com.xcong.excoin.modules.platform.entity.PlatformFeeSettingEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsCoinEntity;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import com.xcong.excoin.utils.RedisUtils;
-import com.xcong.excoin.utils.ShareCodeUtil;
-import com.xcong.excoin.utils.ThreadPoolUtils;
-import lombok.extern.slf4j.Slf4j;
-
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-/**
- * @author wzy
- * @date 2020-05-18
- **/
-@Slf4j
-@Service
-public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {
-
- @Resource
- private MemberDao memberDao;
-
- @Resource
- private MemberWalletAgentDao memberWalletAgentDao;
-
- @Resource
- MemberAccountMoneyChangeDao memberAccountMoneyChangeDao;
-
- @Resource
- private MemberWalletContractDao memberWalletContractDao;
-
- @Resource
- private MemberWalletCoinDao memberWalletCoinDao;
-
- @Resource
- private MemberLevelRateDao memberLevelRateDao;
-
- @Resource
- MemberAuthenticationDao memberAuthenticationDao;
-
- @Resource
- RedisUtils redisUtils;
-
- @Resource
- MemberPaymentMethodDao memberPaymentMethodDao;
-
- @Resource
- PlatformSymbolsCoinDao platformSymbolsCoinDao;
-
- @Resource
- PlatformFeeSettingDao platformFeeSettingDao;
-
- @Resource
- MemberCoinAddressDao memberCoinAddressDao;
-
- @Resource
- private CommonService commonservice;
-
- @Resource
- MemberCoinWithdrawDao memberCoinWithdrawDao;
-
- @Resource
- AppVersionDao appVersionDao;
- @Resource
- private MemberSettingDao memberSettingDao;
-
- @Resource
- private MemberWalletContractSimulateDao memberWalletContractSimulateDao;
-
- @Transactional()
- @Override
- public Result register(RegisterDto registerDto) {
- // 查询是否存在该账号用户
- MemberEntity member = memberDao.selectMemberInfoByAccount(registerDto.getAccount());
- if (member != null) {
- return Result.fail("账号已存在");
- }
-
-// boolean isTrue = commonservice.verifyCode(registerDto.getAccount(), registerDto.getCode());
-// if (!isTrue) {
-// return Result.fail(MessageSourceUtils.getString("common_verify_code"));
-// }
-
- member = new MemberEntity();
- member.setPassword(SecureUtil.md5(registerDto.getPassword()));
-
- // 判断账号类型
- if (MemberEntity.ACCOUNT_TYPE_PHONE.equals(registerDto.getType())) {
- member.setPhone(registerDto.getAccount());
- } else if (MemberEntity.ACCOUNT_TYPE_EMAIL.equals(registerDto.getType())) {
- member.setEmail(registerDto.getAccount());
- } else {
- return Result.fail("账号类型错误");
- }
-
- // 判断是否拥有推荐人,若为空则默认系统
-// if (StrUtil.isBlank(registerDto.getRefererId())) {
-// registerDto.setRefererId(AppContants.SYSTEM_REFERER);
-// }
- if (!AppContants.SYSTEM_REFERER.equals(registerDto.getRefererId())) {
- MemberEntity isExist = memberDao.selectMemberInfoByInviteId(registerDto.getRefererId());
- if (isExist == null) {
- return Result.fail("推荐人不存在");
- }
- }
-
- member.setRefererId(registerDto.getRefererId());
- member.setAccountStatus(MemberEntity.ACCOUNT_STATUS_ENABLE);
- member.setAccountType(MemberEntity.ACCOUNT_TYPE_NORMAL);
- member.setAgentLevel(MemberEntity.ACCOUNT_AGENT_LEVEL);
- member.setCertifyStatus(MemberEntity.CERTIFY_STATUS_UN_SUBMIT);
- member.setIsForce(1);
- member.setIsProfit(0);
- memberDao.insert(member);
-
- MemberSettingEntity memberSettingEntity = new MemberSettingEntity();
- memberSettingEntity.setSpread(BigDecimal.ONE);
- memberSettingEntity.setClosingSpread(BigDecimal.valueOf(5));
- memberSettingEntity.setForceParam(BigDecimal.valueOf(0.0055));
- memberSettingEntity.setMemberId(member.getId());
- memberSettingDao.insert(memberSettingEntity);
-
- String inviteId = ShareCodeUtil.toSerialCode(member.getId());
- member.setInviteId(inviteId);
-
- boolean flag = false;
- String parentId = member.getRefererId();
- String ids = "";
- while (!flag) {
- ids += ("," + parentId);
- MemberEntity parentMember = memberDao.selectMemberInfoByInviteId(parentId);
- if (parentMember == null) {
- break;
- }
- parentId = parentMember.getRefererId();
- if (parentMember.getRefererId().equals(parentMember.getInviteId())) {
- flag = true;
- }
- }
- member.setRefererIds(ids);
- memberDao.updateById(member);
-
- //初始化合约钱包
- MemberWalletContractEntity walletContract = new MemberWalletContractEntity();
- walletContract.setMemberId(member.getId());
- walletContract.setAvailableBalance(AppContants.INIT_MONEY);
- walletContract.setFrozenBalance(AppContants.INIT_MONEY);
- walletContract.setTotalBalance(AppContants.INIT_MONEY);
- walletContract.setBorrowedFund(AppContants.INIT_MONEY);
- walletContract.setWalletCode(CoinTypeEnum.USDT.name());
- memberWalletContractDao.insert(walletContract);
-
- MemberWalletContractSimulateEntity walletContractSimulate = new MemberWalletContractSimulateEntity();
- walletContractSimulate.setMemberId(member.getId());
- walletContractSimulate.setAvailableBalance(new BigDecimal(AppContants.INIT_SIMULATE_MONEY));
- walletContractSimulate.setTotalBalance(new BigDecimal(AppContants.INIT_SIMULATE_MONEY));
- walletContractSimulate.setFrozenBalance(AppContants.INIT_MONEY);
- walletContractSimulate.setBorrowedFund(AppContants.INIT_MONEY);
- walletContractSimulate.setWalletCode(CoinTypeEnum.USDT.name());
- memberWalletContractSimulateDao.insert(walletContractSimulate);
-
-
- // 初始化币币钱包
- for (CoinTypeEnum coinTypeEnum : CoinTypeEnum.values()) {
- MemberWalletCoinEntity walletCoin = new MemberWalletCoinEntity();
- walletCoin.setWalletCode(coinTypeEnum.name());
- walletCoin.setMemberId(member.getId());
- walletCoin.setAvailableBalance(AppContants.INIT_MONEY);
- walletCoin.setFrozenBalance(AppContants.INIT_MONEY);
- walletCoin.setTotalBalance(AppContants.INIT_MONEY);
- walletCoin.setBorrowedFund(AppContants.INIT_MONEY);
- memberWalletCoinDao.insert(walletCoin);
- }
-
- // 初始化代理佣金钱包
- MemberWalletAgentEntity walletAgent = new MemberWalletAgentEntity();
- walletAgent.setMemberId(member.getId());
- walletAgent.setWalletCode(CoinTypeEnum.USDT.name());
- memberWalletAgentDao.insert(walletAgent);
-
- // 初始化杠杆
- for (SymbolEnum symbolEnum : SymbolEnum.values()) {
- MemberLevelRateEntity levelRate = new MemberLevelRateEntity();
- levelRate.setMemberId(member.getId());
- levelRate.setSymbol(symbolEnum.getValue());
- memberLevelRateDao.insert(levelRate);
- }
-
- return Result.ok(MessageSourceUtils.getString("home_service_0009"));
- }
-
- @Override
- public Result getMemberInfo() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity memberEntity = memberDao.selectById(memberId);
- MemberInfoVo memberInfoVo = new MemberInfoVo();
- if (ObjectUtil.isNotEmpty(memberEntity)) {
- String email = memberEntity.getEmail();
- String phone = memberEntity.getPhone();
- if (StrUtil.isNotEmpty(phone)) {
- memberInfoVo.setPhone(phone);
- } else if (StrUtil.isNotEmpty(email)) {
- memberInfoVo.setPhone(email);
- }
-
- memberInfoVo.setInviteId(memberEntity.getInviteId());
- }
- return Result.ok(memberInfoVo);
- }
-
- @Override
- @Transactional
- public Result memberForgetPwd(@Valid MemberForgetPwdDto memberForgetPwdDto) {
-
- int type = memberForgetPwdDto.getType();
- String account = memberForgetPwdDto.getAccount();
- String code = memberForgetPwdDto.getCode();
- String password = memberForgetPwdDto.getPassword();
-
- Map<String, Object> hashMap = new HashMap<>();
- if (type == 1) {
- hashMap.put("phone", account);
- } else {
- hashMap.put("email", account);
- }
- List<MemberEntity> member = memberDao.selectByMap(hashMap);
- if (CollUtil.isEmpty(member)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0047"));
- }
-
- boolean flag = commonservice.verifyCode(account, code);
- if (flag) {
- MemberEntity memberEntity = member.get(0);
- memberEntity.setPassword(SecureUtil.md5(password));
- memberDao.updateById(memberEntity);
- } else {
- return Result.fail(MessageSourceUtils.getString("member_service_0045"));
- }
- return Result.ok(MessageSourceUtils.getString("member_service_0048"));
- }
-
- @Override
- @Transactional
- public Result memberUpdatePwd(@Valid MemberUpdatePwdDto memberUpdatePwdDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity memberEntity = memberDao.selectById(memberId);
-
- String code = memberUpdatePwdDto.getCode();
- String password = memberUpdatePwdDto.getPassword();
- String phone = memberUpdatePwdDto.getPhone();
- String email = memberUpdatePwdDto.getEmail();
- int type = memberUpdatePwdDto.getType();
- boolean verificationCode = verificationCode(type, phone, code, email);
- if (verificationCode) {
- memberEntity.setPassword(SecureUtil.md5(password));
- memberDao.updateById(memberEntity);
- } else {
- return Result.fail(MessageSourceUtils.getString("member_service_0041"));
- }
- return Result.ok(MessageSourceUtils.getString("member_service_0040"));
- }
-
- /**
- * 验证输入的验证码
- *
- * @param type 验证类型1:电话2:邮箱
- * @param phone
- * @param email
- * @param code 验证码
- * @return
- */
- private boolean verificationCode(Integer type, String phone, String code, String email) {
- boolean verificationCode = false;
- if (type == 1) {
- String smsCode = redisUtils.get("SMS_" + phone) + "";
- if (code.equals(smsCode)) {
- verificationCode = true;
- }
- } else {
- String emailCode = redisUtils.get("EMAIL_" + email) + "";
- if (code.equals(emailCode)) {
- verificationCode = true;
- }
- }
- return verificationCode;
- }
-
- @Override
- @Transactional
- public Result memberAuthentication(@Valid MemberAuthenticationDto memberAuthenticationDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
- if (MemberEntity.CERTIFY_STATUS_ING.equals(member.getCertifyStatus())) {
- return Result.fail(MessageSourceUtils.getString("member_service_4000"));
- }
- if (ObjectUtil.isNotEmpty(member)) {
-
- MemberAuthenticationEntity memberAuthenticationEntity = new MemberAuthenticationEntity();
-
- if (MemberEntity.CERTIFY_STATUS_Y == member.getCertifyStatus()) {
- return Result.fail(MessageSourceUtils.getString("member_service_0055"));
- }
- if (MemberEntity.CERTIFY_STATUS_ING == member.getCertifyStatus()) {
- return Result.fail(MessageSourceUtils.getString("member_service_0056"));
- }
- memberAuthenticationEntity.setMemberId(memberId);
-
- if (StrUtil.isBlank(memberAuthenticationDto.getNation())) {
- return Result.fail(MessageSourceUtils.getString("member_service_0057"));
- }
- memberAuthenticationEntity.setNation(memberAuthenticationDto.getNation());
-
- if (StrUtil.isBlank(memberAuthenticationDto.getFirstName())) {
- return Result.fail(MessageSourceUtils.getString("member_service_0058"));
- }
- memberAuthenticationEntity.setFirstName(memberAuthenticationDto.getFirstName());
-
- if (StrUtil.isBlank(memberAuthenticationDto.getSecondName())) {
- return Result.fail(MessageSourceUtils.getString("member_service_0059"));
- }
- memberAuthenticationEntity.setSecondName(memberAuthenticationDto.getSecondName());
-
- String type = memberAuthenticationDto.getType();
- memberAuthenticationEntity.setType(type);
-
- String idCardNo = memberAuthenticationDto.getIdCardNo();
- if (StrUtil.isBlank(idCardNo)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0060"));
- }
- memberAuthenticationEntity.setIdcardNo(idCardNo);
- //同一个身份证号码不能重复实名认证
- int count = memberAuthenticationDao.findMemberbyIdCardNoCount(idCardNo);
- if (count > 0) {
- return Result.fail(MessageSourceUtils.getString("member_service_0060"));
- }
- if (StrUtil.isBlank(memberAuthenticationDto.getIdCardFront())
- || StrUtil.isBlank(memberAuthenticationDto.getIdCardReverse())
- || StrUtil.isBlank(memberAuthenticationDto.getIdCardImage())) {
- return Result.fail(MessageSourceUtils.getString("member_service_0061"));
- }
- memberAuthenticationEntity.setIdcardImageFront(memberAuthenticationDto.getIdCardFront());
- memberAuthenticationEntity.setIdcardImageBack(memberAuthenticationDto.getIdCardReverse());
- memberAuthenticationEntity.setIdcardImageInHand(memberAuthenticationDto.getIdCardImage());
-
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("member_id", memberId);
- List<MemberAuthenticationEntity> selectByMap = memberAuthenticationDao.selectByMap(columnMap);
- if (CollUtil.isEmpty(selectByMap)) {
- memberAuthenticationDao.insert(memberAuthenticationEntity);
- } else {
- memberAuthenticationEntity.setId(selectByMap.get(0).getId());
- memberAuthenticationDao.updateById(memberAuthenticationEntity);
- }
-
- member.setCertifyStatus(MemberEntity.CERTIFY_STATUS_ING);
- member.setIdcardNo(idCardNo);
- memberDao.updateById(member);
-
- ThreadPoolUtils.sendDingTalk(4);
- return Result.ok(MessageSourceUtils.getString("member_service_0024"));
- }
- return Result.fail(MessageSourceUtils.getString("member_service_0063"));
- }
-
- @Override
- @Transactional
- public Result memberUpdateTradePwd(@Valid MemberUpdateTradePwdDto memberUpdateTradePwdDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity memberEntity = memberDao.selectById(memberId);
-
- String code = memberUpdateTradePwdDto.getCode();
- String password = memberUpdateTradePwdDto.getPassword();
- String account = memberUpdateTradePwdDto.getAccount();
- String phone = memberEntity.getPhone();
- String email = memberEntity.getEmail();
- int type = memberUpdateTradePwdDto.getType();
-
- //验证手机号或者邮箱是否是该账户绑定的手机号或者邮箱
- if (MemberEntity.ACCOUNT_TYPE_PHONE.equals(type) && !phone.equals(account)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0041"));
- }
- if (MemberEntity.ACCOUNT_TYPE_EMAIL.equals(type) && !email.equals(account)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0041"));
- }
-
- boolean flag = commonservice.verifyCode(account, code);
- if (flag) {
- memberEntity.setTradePassword(SecureUtil.md5(password));
- memberDao.updateById(memberEntity);
- LoginUserUtils.resetAppLoginUser(memberEntity);
- return Result.ok(MessageSourceUtils.getString("member_service_0051"));
- }
- return Result.fail(MessageSourceUtils.getString("member_service_0045"));
-
- }
-
- @Override
- @Transactional
- public Result memberLogout() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity memberEntity = memberDao.selectById(memberId);
- if (ObjectUtil.isEmpty(memberEntity)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0003"));
- }
- String token = LoginUserUtils.getAppLoginUserToken();
- redisUtils.del(AppContants.APP_LOGIN_PREFIX + token);
- SecurityContextHolder.clearContext();
- return Result.ok(MessageSourceUtils.getString("member_service_0071"));
- }
-
- @Override
- @Transactional
- public Result memberTradersPwd(@Valid MemberForgetPwdDto memberForgetPwdDto) {
- //获取用户ID
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
-
- String code = memberForgetPwdDto.getCode();
- String password = memberForgetPwdDto.getPassword();
- String account = memberForgetPwdDto.getAccount();
- int type = memberForgetPwdDto.getType();
-
- boolean flag = commonservice.verifyCode(account, code);
- if (flag) {
- memberEntity.setTradePassword(SecureUtil.md5(password));
- memberDao.updateById(memberEntity);
- // 重置内存中的用户信息
- LoginUserUtils.resetAppLoginUser(memberEntity);
- } else {
- return Result.fail(MessageSourceUtils.getString("member_service_0015"));
- }
-
- return Result.ok(MessageSourceUtils.getString("member_service_0068"));
- }
-
- @Override
- @Transactional
- public Result memberAddPaymethod(@Valid MemberPaymethodDto memberPaymethodDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
-
- if (!MemberEntity.CERTIFY_STATUS_Y.equals(member.getCertifyStatus())) {
- return Result.fail(MessageSourceUtils.getString("member_service_0077"));
- }
-
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("member_id", memberId);
- List<MemberPaymentMethodEntity> selectByMap = memberPaymentMethodDao.selectByMap(columnMap);
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (MemberPaymentMethodEntity memberPaymentMethodEntity : selectByMap) {
- if (memberPaymethodDto.getAccount().equals(memberPaymentMethodEntity.getAccount())) {
- return Result.fail(MessageSourceUtils.getString("member_service_0097"));
- }
- }
- }
- String account = memberPaymethodDto.getAccount();
- String bank = memberPaymethodDto.getBank();
- String name = memberPaymethodDto.getName();
- String paymentQrcode = memberPaymethodDto.getPaymentQrcode();
- String paymentType = memberPaymethodDto.getPaymentType();
- String subBank = memberPaymethodDto.getSubBank();
- MemberPaymentMethodEntity memberPaymentMethodEntity = new MemberPaymentMethodEntity();
- memberPaymentMethodEntity.setMemberId(memberId);
- memberPaymentMethodEntity.setAccount(account);
- memberPaymentMethodEntity.setBank(bank);
- memberPaymentMethodEntity.setName(name);
- memberPaymentMethodEntity.setPaymentQrcode(paymentQrcode);
- memberPaymentMethodEntity.setPaymentType(paymentType);
- memberPaymentMethodEntity.setSubBank(subBank);
- memberPaymentMethodDao.insert(memberPaymentMethodEntity);
- return Result.ok(MessageSourceUtils.getString("member_service_0024"));
- }
-
- @Override
- @Transactional
- public Result memberDelPaymethod(@Valid MemberDelPaymethodDto memberDelPaymethodDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- Long id = memberDelPaymethodDto.getId();
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("id", id);
- columnMap.put("member_id", memberId);
- memberPaymentMethodDao.deleteByMap(columnMap);
- return Result.ok("success");
- }
-
- @Override
- public Result memberPaymethodDetail(long id) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberPaymentMethodEntity memberPaymentMethod = memberPaymentMethodDao.selectById(id);
-
- MemberPaymethodDetailVo memberPaymethodDetailVo = new MemberPaymethodDetailVo();
- memberPaymethodDetailVo.setAccount(memberPaymentMethod.getAccount());
- memberPaymethodDetailVo.setBank(memberPaymentMethod.getBank());
- memberPaymethodDetailVo.setMemberId(memberId);
- memberPaymethodDetailVo.setName(memberPaymentMethod.getName());
- memberPaymethodDetailVo.setPaymentQrcode(memberPaymentMethod.getPaymentQrcode());
- memberPaymethodDetailVo.setPaymentType(memberPaymentMethod.getPaymentType());
- memberPaymethodDetailVo.setSubBank(memberPaymentMethod.getSubBank());
-
- return Result.ok(memberPaymethodDetailVo);
- }
-
- @Override
- public Result memberPaymethodDetailList() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("member_id", memberId);
- List<MemberPaymentMethodEntity> selectByMap = memberPaymentMethodDao.selectByMap(columnMap);
- List<MemberPaymethodDetailVo> arrayList = new ArrayList<>();
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (MemberPaymentMethodEntity memberPaymentMethodEntity : selectByMap) {
- MemberPaymethodDetailVo memberPaymethodDetailVo = new MemberPaymethodDetailVo();
- memberPaymethodDetailVo.setId(memberPaymentMethodEntity.getId());
- memberPaymethodDetailVo.setAccount(memberPaymentMethodEntity.getAccount());
- memberPaymethodDetailVo.setBank(memberPaymentMethodEntity.getBank());
- memberPaymethodDetailVo.setMemberId(memberId);
- memberPaymethodDetailVo.setName(memberPaymentMethodEntity.getName());
- memberPaymethodDetailVo.setPaymentQrcode(memberPaymentMethodEntity.getPaymentQrcode());
- memberPaymethodDetailVo.setPaymentType(memberPaymentMethodEntity.getPaymentType());
- memberPaymethodDetailVo.setSubBank(memberPaymentMethodEntity.getSubBank());
- arrayList.add(memberPaymethodDetailVo);
- }
- }
-
- MemberPaymethodDetailListVo memberPaymethodDetailListVo = new MemberPaymethodDetailListVo();
- memberPaymethodDetailListVo.setMemberPaymethodDetailVo(arrayList);
- return Result.ok(memberPaymethodDetailListVo);
- }
-
- @Override
- @Transactional
- public Result memberBindPhone(@Valid MemberBindPhoneDto memberBindPhoneDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- String phone = memberBindPhoneDto.getPhone();
- String code = memberBindPhoneDto.getCode();
-
- MemberEntity member = memberDao.selectById(memberId);
-
- if (ObjectUtil.isNotEmpty(member)) {
- if (!commonservice.verifyCode(phone, code)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0013"));
- }
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("phone", phone);
- List<MemberEntity> selectByMap = memberDao.selectByMap(columnMap);
- if (CollUtil.isEmpty(selectByMap)) {
- member.setPhone(phone);
- memberDao.updateById(member);
- return Result.ok(MessageSourceUtils.getString("member_service_0014"));
- } else {
- return Result.fail(MessageSourceUtils.getString("member_service_1400"));
- }
- }
-
- return Result.fail(MessageSourceUtils.getString("member_service_0015"));
- }
-
- @Override
- @Transactional
- public Result memberBindEmail(@Valid MemberBindEmailDto memberBindEmailDto) {
-
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- String email = memberBindEmailDto.getEmail();
- String code = memberBindEmailDto.getCode();
-
- MemberEntity member = memberDao.selectById(memberId);
- boolean flag = commonservice.verifyCode(email, code);
- if (ObjectUtil.isNotEmpty(member)) {
- if (flag) {
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("email", email);
- List<MemberEntity> selectByMap = memberDao.selectByMap(columnMap);
- if (CollUtil.isEmpty(selectByMap)) {
- member.setEmail(email);
- memberDao.updateById(member);
- return Result.ok(MessageSourceUtils.getString("member_service_0018"));
- } else {
- return Result.fail(MessageSourceUtils.getString("member_service_1400"));
- }
- }
- }
- return Result.fail(MessageSourceUtils.getString("member_service_0019"));
- }
-
- @Override
- public Result memberCoinAddressCount() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- List<MemberCoinAddressCountVo> list = platformSymbolsCoinDao.selectCoinAddressCount(memberId);
- MemberCoinAddressCountListVo memberCoinAddressCountListVo = new MemberCoinAddressCountListVo();
- if (CollUtil.isNotEmpty(list)) {
- memberCoinAddressCountListVo.setMemberCoinAddressCountVo(list);
- return Result.ok(memberCoinAddressCountListVo);
- }
- return Result.fail(MessageSourceUtils.getString("member_service_0020"));
- }
-
- @Override
- public Result memberCoinAddressList(String symbol) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- List<MemberCoinAddressEntity> selectByMap = memberCoinAddressDao.selectCoinAddressListByMap(symbol, memberId);
- MemberCoinAddressListVo memberCoinAddressListVo = new MemberCoinAddressListVo();
- List<MemberCoinAddressVo> arrayList = new ArrayList<>();
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (MemberCoinAddressEntity memberCoinAddressEntity : selectByMap) {
- MemberCoinAddressVo memberCoinAddressVo = new MemberCoinAddressVo();
- memberCoinAddressVo.setId(memberCoinAddressEntity.getId());
- memberCoinAddressVo.setAddress(memberCoinAddressEntity.getAddress());
- memberCoinAddressVo.setIsBiyict(memberCoinAddressEntity.getIsBiyict());
- memberCoinAddressVo.setMemberId(memberCoinAddressEntity.getMemberId());
- memberCoinAddressVo.setPrivateKey(memberCoinAddressEntity.getPrivateKey());
- memberCoinAddressVo.setSymbol(memberCoinAddressEntity.getSymbol());
- memberCoinAddressVo.setLabel(memberCoinAddressEntity.getLabel());
- memberCoinAddressVo.setSymbolscoinId(memberCoinAddressEntity.getSymbolscoinId());
- arrayList.add(memberCoinAddressVo);
- }
- }
- memberCoinAddressListVo.setMemberCoinAddressVo(arrayList);
-
- return Result.ok(memberCoinAddressListVo);
- }
-
- @Override
- @Transactional
- public Result memberAddCoinAddress(@Valid MemberAddCoinAddressDto memberAddCoinAddressDto) {
-
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- String address = memberAddCoinAddressDto.getAddress();
- String isBiyict = memberAddCoinAddressDto.getIsBiyict();
- Long symbolscoinId = memberAddCoinAddressDto.getSymbolscoinId();
- String remark = memberAddCoinAddressDto.getRemark();
-
- PlatformSymbolsCoinEntity platformSymbolsCoinEntity = platformSymbolsCoinDao.selectById(symbolscoinId);
-
- MemberCoinAddressEntity memberCoinAddressEntity = new MemberCoinAddressEntity();
- memberCoinAddressEntity.setAddress(address);
- memberCoinAddressEntity.setMemberId(memberId);
- memberCoinAddressEntity.setIsBiyict(MemberCoinAddressEntity.IS_BIYICT_NO);
- memberCoinAddressEntity.setSymbolscoinId(symbolscoinId);
- memberCoinAddressEntity.setLabel(remark);
- memberCoinAddressEntity.setSymbol(platformSymbolsCoinEntity.getName());
-
- memberCoinAddressDao.insert(memberCoinAddressEntity);
-
- return Result.ok(MessageSourceUtils.getString("member_service_0024"));
- }
-
- @Override
- public Result memberSendCodeWay() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
- MemberSendCodeWayVo memberSendCodeWayVo = new MemberSendCodeWayVo();
- if (ObjectUtil.isNotEmpty(member)) {
- memberSendCodeWayVo.setPhone(member.getPhone());
- memberSendCodeWayVo.setEmail(member.getEmail());
- }
- return Result.ok(memberSendCodeWayVo);
- }
-
- @Override
- @Transactional
- public Result memberDelCoinAddress(@Valid MemberDelCoinAddressDto memberDelCoinAddressDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
- if (ObjectUtil.isNotEmpty(member)) {
- Long id = memberDelCoinAddressDto.getId();
- memberCoinAddressDao.deleteById(id);
- }
- return Result.ok("success");
- }
-
- @Override
- public Result memberAuthenticationInfo() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
-
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("member_id", memberId);
- List<MemberAuthenticationEntity> selectByMap = memberAuthenticationDao.selectByMap(columnMap);
-
- MemberAuthenticationInfoVo memberAuthnticationInfoVo = new MemberAuthenticationInfoVo();
- memberAuthnticationInfoVo.setCertifyStatus(member.getCertifyStatus());
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (MemberAuthenticationEntity memberAuthenticationEntity : selectByMap) {
- memberAuthnticationInfoVo.setFirstName(memberAuthenticationEntity.getFirstName());
- memberAuthnticationInfoVo.setSecondName(memberAuthenticationEntity.getSecondName());
- memberAuthnticationInfoVo.setNation(memberAuthenticationEntity.getNation());
- memberAuthnticationInfoVo.setIdCardNo(memberAuthenticationEntity.getIdcardNo());
- memberAuthnticationInfoVo.setType(memberAuthenticationEntity.getType());
- }
- }
- return Result.ok(memberAuthnticationInfoVo);
- }
-
- @Override
- public Result memberPersonCenterInfo() {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
-
- MemberPersonCenterInfoVo memberPersonCenterInfoVo = new MemberPersonCenterInfoVo();
-
- Integer certifyStatus = member.getCertifyStatus();
- memberPersonCenterInfoVo.setCertifyStatus(certifyStatus);
-
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("member_id", memberId);
- List<MemberPaymentMethodEntity> selectByMap = memberPaymentMethodDao.selectByMap(columnMap);
- if (CollUtil.isEmpty(selectByMap)) {
- memberPersonCenterInfoVo.setMemberPaymentMethod(0);
- } else {
- memberPersonCenterInfoVo.setMemberPaymentMethod(1);
- }
-
- if (StrUtil.isNotEmpty(member.getPhone())) {
- memberPersonCenterInfoVo.setPhone(1);
- } else {
- memberPersonCenterInfoVo.setPhone(0);
- }
-
- if (StrUtil.isNotEmpty(member.getEmail())) {
- memberPersonCenterInfoVo.setEmail(1);
- } else {
- memberPersonCenterInfoVo.setEmail(0);
- }
-
- if (StrUtil.isNotEmpty(member.getTradePassword())) {
- memberPersonCenterInfoVo.setTradePassword(1);
- } else {
- memberPersonCenterInfoVo.setTradePassword(0);
- }
-
- Integer tradeAgingSetting = member.getTradeAgingSetting();
- if (tradeAgingSetting != null && tradeAgingSetting == MemberPersonCenterInfoVo.PWD_NEED_FORVER) {
- memberPersonCenterInfoVo.setTradeAgingSetting(MemberPersonCenterInfoVo.PWD_NEED_FORVER);
- } else {
- memberPersonCenterInfoVo.setTradeAgingSetting(MemberPersonCenterInfoVo.PWD_NEED_NO);
- }
-
- return Result.ok(memberPersonCenterInfoVo);
- }
-
- @Override
- public Result memberCoinInfoList() {
-
- MemberCoinInfoListVo memberCoinInfoListVo = new MemberCoinInfoListVo();
- List<PlatformSymbolsCoinEntity> selectByMap = platformSymbolsCoinDao.selectByMap(new HashMap<>());
- List<MemberCoinInfoVo> arrayList = new ArrayList<>();
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (PlatformSymbolsCoinEntity platformSymbolsCoinEntity : selectByMap) {
- MemberCoinInfoVo memberCoinInfoVo = new MemberCoinInfoVo();
- memberCoinInfoVo.setName(platformSymbolsCoinEntity.getName());
- arrayList.add(memberCoinInfoVo);
- }
- }
- memberCoinInfoListVo.setMemberCoinInfoVo(arrayList);
-
- return Result.ok(memberCoinInfoListVo);
- }
-
- @Override
- public Result memberAvivableCoinInfo(String symbol) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, symbol);
- if (ObjectUtil.isEmpty(walletCoin)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0087"));
- }
-
- List<MemberAvivableCoinInfoVo> arrayList = new ArrayList<>();
-
-
- List<PlatformFeeSettingEntity> feeSettingByTypeAndSymbolLable = platformFeeSettingDao.getFeeSettingsByTypeAndSymbol(2, symbol);
- if (CollUtil.isEmpty(feeSettingByTypeAndSymbolLable)) {
- return Result.fail(MessageSourceUtils.getString("member_service_0087"));
- }
- for (PlatformFeeSettingEntity platformFeeSettingEntity : feeSettingByTypeAndSymbolLable) {
- MemberAvivableCoinInfoVo memberAvivableCoinInfoVo = new MemberAvivableCoinInfoVo();
- memberAvivableCoinInfoVo.setAvailableBalance(walletCoin.getAvailableBalance());
- memberAvivableCoinInfoVo.setFee(platformFeeSettingEntity.getFeePrice());
- memberAvivableCoinInfoVo.setLable(platformFeeSettingEntity.getLable());
- arrayList.add(memberAvivableCoinInfoVo);
- }
-
- return Result.ok(arrayList);
- }
-
- @Override
- public NeedMoneyMemberVo selectFriendRelationUserByMemberId(Long memberId) {
- return memberDao.selectFriendRelationUserByMemberId(memberId);
- }
-
- @Override
- public List<NeedMoneyMemberVo> selectAllNeedMoneyMember(List<String> list) {
- return memberDao.selectAllNeedMoneyMember(list);
- }
-
- @Override
- public MemberEntity selectMemberInfoByInviteId(String inviteId) {
- return memberDao.selectMemberInfoByInviteId(inviteId);
- }
-
- @Override
- @Transactional
- public Result memberUpdateTradersPwdTime(MemberUpdateTradersPwdTimeDto memberUpdateTradersPwdTimeDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
- member.setTradeAgingSetting(memberUpdateTradersPwdTimeDto.getTradeAgingSetting());
- memberDao.updateById(member);
- return Result.ok("success");
- }
-
- @Override
- public Result memberSubmitCoinApply(@Valid MemberSubmitCoinApplyDto memberSubmitCoinApplyDto) {
- //获取用户ID
- Long memberId = LoginUserUtils.getAppLoginUser().getId();
- MemberEntity member = memberDao.selectById(memberId);
- if (member.getCertifyStatus() != MemberEntity.CERTIFY_STATUS_Y) {
- return Result.fail(MessageSourceUtils.getString("member_service_0077"));
- }
- if (StrUtil.isEmpty(member.getTradePassword())) {
- return Result.fail(MessageSourceUtils.getString("member_service_0081"));
- }
- if (member.getTradePassword() == null) {
- return Result.fail(MessageSourceUtils.getString("member_service_0082"));
- }
- if (!member.getTradePassword().equals(SecureUtil.md5(memberSubmitCoinApplyDto.getTradePassword()))) {
- return Result.fail(MessageSourceUtils.getString("member_service_0082"));
- }
-
- boolean flag = commonservice.verifyCode(memberSubmitCoinApplyDto.getAccount(), memberSubmitCoinApplyDto.getCode());
- if (flag) {
- MemberWalletCoinEntity walletCoin = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, memberSubmitCoinApplyDto.getSymbol());
- BigDecimal availableBalance = walletCoin.getAvailableBalance();
- BigDecimal coinNumber = memberSubmitCoinApplyDto.getCoinNumber();
- if (availableBalance.compareTo(BigDecimal.ZERO) > 0
- && availableBalance.compareTo(coinNumber) >= 0) {
- //新增提币记录
- MemberCoinWithdrawEntity memberCoinWithdrawEntity = new MemberCoinWithdrawEntity();
- memberCoinWithdrawEntity.setAddress(memberSubmitCoinApplyDto.getAddress());
- memberCoinWithdrawEntity.setAmount(coinNumber);
- memberCoinWithdrawEntity.setFeeAmount(memberSubmitCoinApplyDto.getFeeAmount());
- memberCoinWithdrawEntity.setSymbol(memberSubmitCoinApplyDto.getSymbol());
- memberCoinWithdrawEntity.setMemberId(memberId);
- memberCoinWithdrawEntity.setStatus(MemberCoinWithdrawEntity.STATUS_DOING);
-
- Map<String, Object> columnMap = new HashMap<>();
- columnMap.put("symbol", memberSubmitCoinApplyDto.getSymbol());
- columnMap.put("address", memberSubmitCoinApplyDto.getAddress());
- columnMap.put("is_biyict", MemberCoinAddressEntity.IS_BIYICT_YES);
- List<MemberCoinAddressEntity> selectByMap = memberCoinAddressDao.selectByMap(columnMap);
- if (CollUtil.isEmpty(selectByMap)) {
- memberCoinWithdrawEntity.setIsInside(MemberCoinWithdrawEntity.ISINSIDE_NO);
- } else {
- memberCoinWithdrawEntity.setIsInside(MemberCoinWithdrawEntity.ISINSIDE_YES);
- }
- memberCoinWithdrawDao.insert(memberCoinWithdrawEntity);
- BigDecimal subtract = walletCoin.getAvailableBalance().subtract(coinNumber);
- walletCoin.setAvailableBalance(subtract);
- BigDecimal add = walletCoin.getFrozenBalance().add(coinNumber);
- walletCoin.setFrozenBalance(add);
- memberWalletCoinDao.updateById(walletCoin);
-
- MemberAccountMoneyChange accountRecord = new MemberAccountMoneyChange();
- accountRecord.setContent("提币");
- accountRecord.setMemberId(memberId);
- accountRecord.setAmount(coinNumber);
- accountRecord.setWithdrawId(memberCoinWithdrawEntity.getId());
- accountRecord.setStatus(MemberAccountMoneyChange.STATUS_WAIT_INTEGER);
- accountRecord.setSymbol(memberSubmitCoinApplyDto.getSymbol());
- accountRecord.setType(MemberAccountMoneyChange.TYPE_WALLET_COIN);
- memberAccountMoneyChangeDao.insert(accountRecord);
-
- ThreadPoolUtils.sendDingTalk(3);
- return Result.ok(MessageSourceUtils.getString("member_service_0086"));
- } else {
- return Result.fail(MessageSourceUtils.getString("member_service_0005"));
- }
-
- } else {
- return Result.fail(MessageSourceUtils.getString("member_service_0039"));
- }
- }
-
- @Override
- public Result getMemberAccountInfo(String account, int type) {
-
- Map<String, Object> hashMap = new HashMap<>();
- if (type == 1) {
- hashMap.put("phone", account);
- } else {
- hashMap.put("email", account);
- }
- List<MemberEntity> member = memberDao.selectByMap(hashMap);
- if (CollUtil.isEmpty(member)) {
- return Result.fail(MessageSourceUtils.getString("home_service_0003"));
- }
-
- return Result.ok("");
- }
-
- @Override
- public Result getAppVersionInfo() {
- MemberEntity memberEntity = LoginUserUtils.getAppLoginUser();
-
- Map<String, Object> columnMap = new HashMap<>();
- List<AppVersionEntity> selectByMap = appVersionDao.selectByMap(columnMap);
- List<Object> arrayList = new ArrayList<>();
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (AppVersionEntity appVersionEntity : selectByMap) {
- AppVersionVo appVersionVo = new AppVersionVo();
- if ("37059551".equals(memberEntity.getInviteId())) {
- appVersionVo.setAddress("www.baidu.com");
- appVersionVo.setType(appVersionEntity.getType());
- appVersionVo.setVersion(appVersionEntity.getVersion());
- } else {
- appVersionVo.setAddress(appVersionEntity.getAddress());
- appVersionVo.setType(appVersionEntity.getType());
- appVersionVo.setVersion(appVersionEntity.getVersion());
- }
- arrayList.add(appVersionVo);
- }
- }
- return Result.ok(arrayList);
- }
-
- @Override
- public Result getPcVersionInfo() {
- Map<String, Object> columnMap = new HashMap<>();
- List<AppVersionEntity> selectByMap = appVersionDao.selectByMap(columnMap);
- List<Object> arrayList = new ArrayList<>();
- if (CollUtil.isNotEmpty(selectByMap)) {
- for (AppVersionEntity appVersionEntity : selectByMap) {
- AppVersionVo appVersionVo = new AppVersionVo();
- appVersionVo.setAddress(appVersionEntity.getAddress());
- appVersionVo.setType(appVersionEntity.getType());
- appVersionVo.setVersion(appVersionEntity.getVersion());
- arrayList.add(appVersionVo);
- }
- }
- return Result.ok(arrayList);
- }
-}
-
-
diff --git a/src/main/java/com/xcong/excoin/modules/member/service/impl/MemberWalletContractServiceImpl.java b/src/main/java/com/xcong/excoin/modules/member/service/impl/MemberWalletContractServiceImpl.java
deleted file mode 100644
index 9a7abac..0000000
--- a/src/main/java/com/xcong/excoin/modules/member/service/impl/MemberWalletContractServiceImpl.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.xcong.excoin.modules.member.service.impl;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-import com.xcong.excoin.modules.member.service.MemberWalletContractService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-
-/**
- * 会员合约钱包
- */
-@Slf4j
-@Service
-public class MemberWalletContractServiceImpl extends ServiceImpl<MemberWalletContractDao, MemberWalletContractEntity> implements MemberWalletContractService {
-
- @Resource
- private MemberWalletContractDao memberWalletContractDao;
-
- @Override
- public MemberWalletContractEntity findWalletContractByMemberIdAndSymbol(Long memberId, String symbol){
- return memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId,symbol);
- }
-
- @Override
- public void increaseWalletContractBalanceById(BigDecimal availableBalance, BigDecimal totalBalance, BigDecimal frozenBalance, Long id) {
- memberWalletContractDao.increaseWalletContractBalanceById(availableBalance,totalBalance,frozenBalance,id);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/newPrice/OkxNewPriceWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/newPrice/OkxNewPriceWebSocketClient.java
deleted file mode 100644
index 27b97d9..0000000
--- a/src/main/java/com/xcong/excoin/modules/newPrice/OkxNewPriceWebSocketClient.java
+++ /dev/null
@@ -1,321 +0,0 @@
-package com.xcong.excoin.modules.newPrice;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig;
-import com.xcong.excoin.rabbit.pricequeue.WebsocketPriceService;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.handshake.ServerHandshake;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.annotation.Resource;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * OKX 新价格 WebSocket 客户端类,用于连接 OKX 的 WebSocket 接口,
- * 实时获取并处理标记价格(mark price)数据,并将价格信息存储到 Redis 中。
- * 同时支持心跳检测、自动重连以及异常恢复机制。
- * @author Administrator
- */
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "websocket", havingValue = "true")
-public class OkxNewPriceWebSocketClient {
- @Resource
- private WebsocketPriceService websocketPriceService;
- @Resource
- private RedisUtils redisUtils;
-
- private WebSocketClient webSocketClient;
- private ScheduledExecutorService heartbeatExecutor;
- private volatile ScheduledFuture<?> pongTimeoutFuture;
- private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
-
- private static final String CHANNEL = "mark-price";
-
- // 心跳超时时间(秒),小于30秒
- private static final int HEARTBEAT_TIMEOUT = 10;
-
- // 共享线程池用于重连等异步任务
- private final ExecutorService sharedExecutor = Executors.newCachedThreadPool(r -> {
- Thread t = new Thread(r, "okx-ws-shared-worker");
- t.setDaemon(true);
- return t;
- });
-
- /**
- * 初始化方法,在 Spring Bean 构造完成后执行。
- * 负责建立 WebSocket 连接并启动心跳检测任务。
- */
- @PostConstruct
- public void init() {
- connect();
- startHeartbeat();
- }
-
- /**
- * 销毁方法,在 Spring Bean 销毁前执行。
- * 关闭 WebSocket 连接、停止心跳定时器及相关的线程资源。
- */
- @PreDestroy
- public void destroy() {
- if (webSocketClient != null && webSocketClient.isOpen()) {
- webSocketClient.close();
- }
- if (heartbeatExecutor != null) {
- heartbeatExecutor.shutdownNow();
- }
- if (pongTimeoutFuture != null) {
- pongTimeoutFuture.cancel(true);
- }
- sharedExecutor.shutdownNow();
- }
- private static final String WS_URL_MONIPAN = "wss://wspap.okx.com:8443/ws/v5/public";
- private static final String WS_URL_SHIPAN = "wss://ws.okx.com:8443/ws/v5/public";
- private static final boolean isAccountType = false;
-
- /**
- * 建立与 OKX WebSocket 服务器的连接。
- * 设置回调函数以监听连接打开、接收消息、关闭和错误事件。
- */
- private void connect() {
- try {
- SSLConfig.configureSSL();
- System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
- String WS_URL = WS_URL_MONIPAN;
- if (isAccountType){
- WS_URL = WS_URL_SHIPAN;
- }
- URI uri = new URI(WS_URL);
- webSocketClient = new WebSocketClient(uri) {
- @Override
- public void onOpen(ServerHandshake handshake) {
- log.info("OKX New Price WebSocket连接成功");
- resetHeartbeatTimer();
- subscribeChannels();
- }
-
- @Override
- public void onMessage(String message) {
- lastMessageTime.set(System.currentTimeMillis());
- handleWebSocketMessage(message);
- resetHeartbeatTimer();
- }
-
- @Override
- public void onClose(int code, String reason, boolean remote) {
- log.warn("OKX New Price WebSocket连接关闭: code={}, reason={}", code, reason);
- cancelPongTimeout();
-
- sharedExecutor.execute(() -> {
- try {
- reconnectWithBackoff();
- } catch (InterruptedException ignored) {
- Thread.currentThread().interrupt();
- } catch (Exception e) {
- log.error("重连失败", e);
- }
- });
- }
-
- @Override
- public void onError(Exception ex) {
- log.error("OKX New Price WebSocket发生错误", ex);
- }
- };
-
- webSocketClient.connect();
- } catch (URISyntaxException e) {
- log.error("WebSocket URI格式错误", e);
- }
- }
-
- /**
- * 订阅指定交易对的价格通道。
- * 构造订阅请求并发送给服务端。
- */
- private void subscribeChannels() {
- JSONObject subscribeMsg = new JSONObject();
- subscribeMsg.put("op", "subscribe");
-
- JSONArray argsArray = new JSONArray();
- JSONObject arg = new JSONObject();
- arg.put("channel", CHANNEL);
- arg.put("instId", CoinEnums.HE_YUE.getCode());
- argsArray.add(arg);
-
- subscribeMsg.put("args", argsArray);
- webSocketClient.send(subscribeMsg.toJSONString());
- log.info("已发送价格订阅请求,订阅通道数: {}", argsArray.size());
- }
-
- /**
- * 处理从 WebSocket 收到的消息。
- * 包括订阅确认、错误响应、心跳响应以及实际的数据推送。
- *
- * @param message 来自 WebSocket 的原始字符串消息
- */
- private void handleWebSocketMessage(String message) {
- try {
- JSONObject response = JSON.parseObject(message);
- String event = response.getString("event");
-
- if ("subscribe".equals(event)) {
- log.info("价格订阅成功: {}", response.getJSONObject("arg"));
- } else if ("error".equals(event)) {
- log.error("价格订阅错误: code={}, msg={}",
- response.getString("code"), response.getString("msg"));
- } else if ("pong".equals(event)) {
- log.debug("收到pong响应");
- cancelPongTimeout();
- } else {
- processPushData(response);
- }
- } catch (Exception e) {
- log.error("处理WebSocket消息失败: {}", message, e);
- }
- }
-
- /**
- * 解析并处理价格推送数据。
- * 将最新的标记价格存入 Redis 并触发后续业务逻辑比较处理。
- *
- * @param response 包含价格数据的 JSON 对象
- */
- private void processPushData(JSONObject response) {
- try {
- JSONArray dataArray = response.getJSONArray("data");
- if (dataArray != null && !dataArray.isEmpty()) {
- for (int i = 0; i < dataArray.size(); i++) {
- try {
- JSONObject priceData = dataArray.getJSONObject(i);
- String instId = priceData.getString("instId");
- String markPx = priceData.getString("markPx");
- String ts = priceData.getString("ts");
-
- redisUtils.set(CoinEnums.HE_YUE.getCode(), markPx);
-
- log.debug("更新最新价格: {} = {}, 币种: {}", CoinEnums.HE_YUE.getCode(), markPx, instId);
- } catch (Exception innerEx) {
- log.warn("处理单条价格数据失败", innerEx);
- }
- }
- }
- } catch (Exception e) {
- log.error("处理价格推送数据失败", e);
- }
- }
-
- /**
- * 构建 Redis Key
- */
- private String buildRedisKey(String instId) {
- return "PRICE_" + instId.replace("-", "");
- }
-
- /**
- * 启动心跳检测任务。
- * 使用 ScheduledExecutorService 定期检查是否需要发送 ping 请求来维持连接。
- */
- private void startHeartbeat() {
- if (heartbeatExecutor != null) {
- heartbeatExecutor.shutdownNow();
- }
-
- heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
- Thread t = new Thread(r, "okx-newprice-heartbeat");
- t.setDaemon(true);
- return t;
- });
-
- heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout, 25, 25, TimeUnit.SECONDS);
- }
-
- /**
- * 重置心跳计时器。
- * 当收到新消息或发送 ping 后取消当前超时任务并重新安排下一次超时检查。
- */
- private synchronized void resetHeartbeatTimer() {
- cancelPongTimeout();
-
- if (heartbeatExecutor != null) {
- pongTimeoutFuture = heartbeatExecutor.schedule(this::checkHeartbeatTimeout,
- HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
- }
- }
-
- /**
- * 检查心跳超时情况。
- * 若长时间未收到任何消息则主动发送 ping 请求保持连接活跃。
- */
- private void checkHeartbeatTimeout() {
- long currentTime = System.currentTimeMillis();
- long lastTime = lastMessageTime.get();
-
- if (currentTime - lastTime >= HEARTBEAT_TIMEOUT * 1000L) {
- sendPing();
- }
- }
-
- /**
- * 发送 ping 请求至 WebSocket 服务端。
- * 用于维持长连接有效性。
- */
- private void sendPing() {
- try {
- if (webSocketClient != null && webSocketClient.isOpen()) {
- JSONObject ping = new JSONObject();
- ping.put("op", "ping");
- webSocketClient.send(ping.toJSONString());
- log.debug("发送ping请求");
- }
- } catch (Exception e) {
- log.warn("发送ping失败", e);
- }
- }
-
- /**
- * 取消当前的心跳超时任务。
- * 在收到 pong 或其他有效消息时调用此方法避免不必要的断开重连。
- */
- private synchronized void cancelPongTimeout() {
- if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) {
- pongTimeoutFuture.cancel(true);
- }
- }
-
- /**
- * 执行 WebSocket 重连操作。
- * 在连接意外中断后尝试重新建立连接。
- */
- private void reconnectWithBackoff() throws InterruptedException {
- int attempt = 0;
- int maxAttempts = 3;
- long delayMs = 5000;
-
- while (attempt < maxAttempts) {
- try {
- Thread.sleep(delayMs);
- connect();
- return;
- } catch (Exception e) {
- log.warn("第{}次重连失败", attempt + 1, e);
- delayMs *= 2;
- attempt++;
- }
- }
-
- log.error("超过最大重试次数({})仍未连接成功", maxAttempts);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/newPrice/OkxWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/newPrice/OkxWebSocketClient.java
deleted file mode 100644
index a7aa6d9..0000000
--- a/src/main/java/com/xcong/excoin/modules/newPrice/OkxWebSocketClient.java
+++ /dev/null
@@ -1,352 +0,0 @@
-//package com.xcong.excoin.modules.okxKline;
-//
-//import com.alibaba.fastjson.JSON;
-//import com.alibaba.fastjson.JSONArray;
-//import com.alibaba.fastjson.JSONObject;
-//import com.xcong.excoin.utils.RedisUtils;
-//import lombok.extern.slf4j.Slf4j;
-//import org.java_websocket.client.WebSocketClient;
-//import org.java_websocket.handshake.ServerHandshake;
-//import org.springframework.stereotype.Component;
-//
-//import javax.annotation.PostConstruct;
-//import javax.annotation.PreDestroy;
-//import javax.annotation.Resource;
-//import java.net.URI;
-//import java.net.URISyntaxException;
-//import java.nio.channels.ClosedChannelException;
-//import java.util.HashMap;
-//import java.util.Map;
-//import java.util.concurrent.Executors;
-//import java.util.concurrent.ScheduledExecutorService;
-//import java.util.concurrent.ScheduledFuture;
-//import java.util.concurrent.TimeUnit;
-//import java.util.concurrent.atomic.AtomicReference;
-//
-//@Slf4j
-//@Component
-//public class OkxWebSocketClient {
-//
-// private WebSocketClient webSocketClient;
-// private ScheduledExecutorService heartbeatExecutor;
-// private ScheduledFuture<?> pongTimeoutFuture;
-// private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
-//
-// @Resource
-// private RedisUtils redisUtils;
-//
-// private static final String WS_URL = "wss://ws.okx.com:8443/ws/v5/business";
-//// private static final String WS_URL = "wss://wspap.okx.com:8443/ws/v5/business";
-// private static final String[] CHANNELS = {
-// "mark-price-candle1m", "mark-price-candle5m", "mark-price-candle15m",
-// "mark-price-candle30m", "mark-price-candle1H", "mark-price-candle4H",
-// "mark-price-candle1D"
-// };
-//
-// private static final String[] INST_IDS = {
-// "BTC-USDT", "ETH-USDT", "BNB-USDT", "XRP-USDT", "ADA-USDT",
-// "DOGE-USDT", "DOT-USDT", "UNI-USDT", "LTC-USDT", "LINK-USDT"
-// };
-//
-// // 心跳超时时间(秒),小于30秒
-// private static final int HEARTBEAT_INTERVAL = 25; // 增加到25秒
-// private static final int PONG_TIMEOUT = 15; // 增加到15秒
-//
-// @PostConstruct
-// public void init() {
-// connect();
-// startHeartbeat();
-// }
-//
-// @PreDestroy
-// public void destroy() {
-// if (webSocketClient != null && webSocketClient.isOpen()) {
-// try {
-// webSocketClient.close();
-// } catch (Exception e) {
-// log.warn("关闭WebSocket连接时发生异常", e);
-// }
-// }
-// if (heartbeatExecutor != null) {
-// heartbeatExecutor.shutdown();
-// }
-// if (pongTimeoutFuture != null) {
-// pongTimeoutFuture.cancel(true);
-// }
-// }
-//
-// private void connect() {
-// try {
-// URI uri = new URI(WS_URL);
-// webSocketClient = new WebSocketClient(uri) {
-// @Override
-// public void onOpen(ServerHandshake handshake) {
-// log.info("OKX WebSocket连接成功");
-// lastMessageTime.set(System.currentTimeMillis());
-// subscribeChannels();
-// }
-//
-// @Override
-// public void onMessage(String message) {
-// // 更新最后消息时间
-// lastMessageTime.set(System.currentTimeMillis());
-// handleWebSocketMessage(message);
-// }
-//
-// @Override
-// public void onClose(int code, String reason, boolean remote) {
-// log.warn("OKX WebSocket连接关闭: code={}, reason={}, remote={}", code, reason, remote);
-// cancelPongTimeout();
-// // 不能在WebSocket线程内部直接调用reconnect()方法
-// // 需要在另一个线程中执行重连操作
-// scheduleReconnect();
-// }
-//
-// @Override
-// public void onError(Exception ex) {
-// log.error("OKX WebSocket发生错误", ex);
-// // 特别处理连接异常
-// if (ex instanceof ClosedChannelException) {
-// log.warn("检测到通道关闭,准备重连");
-// scheduleReconnect();
-// }
-// }
-// };
-//
-// webSocketClient.connect();
-// } catch (URISyntaxException e) {
-// log.error("WebSocket URI格式错误", e);
-// }
-// }
-//
-// private void subscribeChannels() {
-// try {
-// JSONObject subscribeMsg = new JSONObject();
-// subscribeMsg.put("op", "subscribe");
-//
-// JSONArray argsArray = new JSONArray();
-// for (String channel : CHANNELS) {
-// for (String instId : INST_IDS) {
-// JSONObject arg = new JSONObject();
-// arg.put("channel", channel);
-// arg.put("instId", instId);
-// argsArray.add(arg);
-// }
-// }
-//
-// subscribeMsg.put("args", argsArray);
-// webSocketClient.send(subscribeMsg.toJSONString());
-// log.info("已发送订阅请求,订阅通道数: {}", argsArray.size());
-// } catch (Exception e) {
-// log.error("发送订阅请求失败", e);
-// }
-// }
-//
-// private void handleWebSocketMessage(String message) {
-// try {
-// JSONObject response = JSON.parseObject(message);
-// String event = response.getString("event");
-//
-// if ("subscribe".equals(event)) {
-// log.info("订阅成功: {}", response.getJSONObject("arg"));
-// } else if ("error".equals(event)) {
-// log.error("订阅错误: code={}, msg={}",
-// response.getString("code"), response.getString("msg"));
-// } else if ("pong".equals(event)) {
-// log.debug("收到pong响应");
-// cancelPongTimeout();
-// } else {
-// // 处理推送数据
-// processPushData(response);
-// }
-// } catch (Exception e) {
-// log.error("处理WebSocket消息失败: {}", message, e);
-// }
-// }
-//
-// private void processPushData(JSONObject response) {
-// try {
-// JSONArray dataArray = response.getJSONArray("data");
-// if (dataArray != null && !dataArray.isEmpty()) {
-// JSONObject arg = response.getJSONObject("arg");
-// String channel = arg.getString("channel");
-// String instId = arg.getString("instId");
-//
-// // 解析K线周期
-// String period = extractPeriodFromChannel(channel);
-//
-// // 处理每条K线数据
-// for (int i = 0; i < dataArray.size(); i++) {
-// JSONArray klineData = dataArray.getJSONArray(i);
-// updateKlineData(instId, period, klineData);
-// }
-// }
-// } catch (Exception e) {
-// log.error("处理推送数据失败", e);
-// }
-// }
-//
-// private String extractPeriodFromChannel(String channel) {
-// // 从channel名称中提取周期标识
-// if (channel.startsWith("mark-price-candle")) {
-// return channel.replace("mark-price-candle", "");
-// }
-// return "1m"; // 默认1分钟
-// }
-//
-// private void updateKlineData(String instId, String period, JSONArray klineData) {
-// try {
-// String timestamp = klineData.getString(0);
-// String open = klineData.getString(1);
-// String high = klineData.getString(2);
-// String low = klineData.getString(3);
-// String close = klineData.getString(4);
-// String confirm = klineData.getString(5); // 0=未完结, 1=已完结
-//
-// // 构造Redis键
-// String redisKey = "KINE_" + instId.replace("-", "") + "_" + period;
-//
-// // 创建K线对象并存储到Redis
-// Map<String, Object> klineMap = new HashMap<>();
-// klineMap.put("ts", timestamp);
-// klineMap.put("o", open);
-// klineMap.put("h", high);
-// klineMap.put("l", low);
-// klineMap.put("c", close);
-// klineMap.put("confirm", confirm);
-//
-// // 如果K线已完结,则更新Redis数据
-// if ("1".equals(confirm)) {
-//// redisUtils.set(redisKey, klineMap);
-// log.debug("更新K线数据: {} -> {}", redisKey, klineMap);
-// }
-//
-// } catch (Exception e) {
-// log.error("更新K线数据失败: instId={}, period={}", instId, period, e);
-// }
-// }
-//
-// private synchronized void startHeartbeat() {
-// if (heartbeatExecutor != null) {
-// heartbeatExecutor.shutdown();
-// try {
-// // 等待现有任务完成,最多等待5秒
-// if (!heartbeatExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
-// heartbeatExecutor.shutdownNow();
-// }
-// } catch (InterruptedException e) {
-// heartbeatExecutor.shutdownNow();
-// Thread.currentThread().interrupt();
-// }
-// }
-//
-// heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
-// Thread thread = new Thread(r, "okx-websocket-heartbeat");
-// thread.setDaemon(true);
-// return thread;
-// });
-//
-// // 定期发送ping消息
-// heartbeatExecutor.scheduleWithFixedDelay(this::checkConnectionAndPing,
-// HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
-// }
-//
-// /**
-// * 检查连接状态并在需要时发送ping
-// */
-// private void checkConnectionAndPing() {
-// try {
-// // 检查连接是否仍然有效
-// if (webSocketClient == null || !webSocketClient.isOpen()) {
-// log.warn("WebSocket连接已断开,准备重连");
-// scheduleReconnect();
-// return;
-// }
-//
-// // 检查上次消息时间,如果太久没有收到消息则发送ping
-// long now = System.currentTimeMillis();
-// long lastTime = lastMessageTime.get();
-// if (now - lastTime > HEARTBEAT_INTERVAL * 1000L) {
-// sendPing();
-// }
-// } catch (Exception e) {
-// log.error("检查连接状态时发生异常", e);
-// }
-// }
-//
-// private void sendPing() {
-// try {
-// if (webSocketClient != null && webSocketClient.isOpen()) {
-// JSONObject ping = new JSONObject();
-// ping.put("op", "ping");
-// webSocketClient.send(ping.toJSONString());
-// log.debug("发送ping请求");
-//
-// // 设置pong超时检查
-// schedulePongTimeout();
-// }
-// } catch (Exception e) {
-// log.warn("发送ping失败", e);
-// // 发送失败时安排重连
-// scheduleReconnect();
-// }
-// }
-//
-// private void schedulePongTimeout() {
-// if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) {
-// pongTimeoutFuture.cancel(true);
-// }
-//
-// if (heartbeatExecutor != null) {
-// pongTimeoutFuture = heartbeatExecutor.schedule(() -> {
-// log.warn("未收到pong响应,准备重新连接");
-// scheduleReconnect();
-// }, PONG_TIMEOUT, TimeUnit.SECONDS);
-// }
-// }
-//
-// private void cancelPongTimeout() {
-// if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) {
-// pongTimeoutFuture.cancel(true);
-// }
-// }
-//
-// /**
-// * 在独立线程中安排重连,避免在WebSocket线程中直接重连
-// */
-// private void scheduleReconnect() {
-// // 使用守护线程执行重连
-// Thread reconnectThread = new Thread(() -> {
-// try {
-// Thread.sleep(5000); // 等待5秒后重连
-// reconnect();
-// } catch (InterruptedException e) {
-// Thread.currentThread().interrupt();
-// log.warn("重连任务被中断");
-// } catch (Exception e) {
-// log.error("重连过程中发生异常", e);
-// }
-// }, "okx-kline-scheduled-reconnect");
-// reconnectThread.setDaemon(true);
-// reconnectThread.start();
-// }
-//
-// private void reconnect() {
-// try {
-// log.info("开始重新连接...");
-// // 先清理旧的连接
-// if (webSocketClient != null) {
-// try {
-// webSocketClient.closeBlocking();
-// } catch (Exception e) {
-// log.warn("关闭旧连接时发生异常", e);
-// }
-// }
-//
-// // 建立新连接
-// connect();
-// } catch (Exception e) {
-// log.error("重连过程中发生异常", e);
-// }
-// }
-//}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/ExchangeInfoEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/ExchangeInfoEnum.java
new file mode 100644
index 0000000..28d723f
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/ExchangeInfoEnum.java
@@ -0,0 +1,73 @@
+package com.xcong.excoin.modules.okxNewPrice;
+
+import lombok.Getter;
+
+/**
+ * 交易信息枚举类
+ * 用于存储不同交易账户的密钥信息,包括实盘账户和模拟账户
+ */
+@Getter
+public enum ExchangeInfoEnum {
+
+ /**
+ * 模拟盘账户1信息
+ * 存储了模拟盘交易所需的API密钥、秘钥和通过码
+ */
+// OKX_PRD_xiao("f512673b-2685-4fcb-9bb1-2ae8db745d62",
+// "B0C1CC8F39625B41140D93DC25039E33",
+// "Aa12345678@",
+// true);
+ OKX_UAT_ceshi("ffb4e79f-fcf5-4afb-82c5-2fbb64123f61",
+ "AA06C5ED1D7C7F5AFE6484052E231C55",
+ "Aa12345678@",
+ false);
+//
+// /**
+// * 模拟盘账户2信息
+// * 存储了模拟盘交易所需的API密钥、秘钥和通过码
+// */
+// OKX_PRD_wang("72e380a6-4133-451b-8b10-8b1905b30717",
+// "2A5BD55BF0771F1ADF08AE0A2FB4D561",
+// "Aa12345678@",
+// true);
+// OKX_UAT2("7a023eb2-06c0-4255-9969-b86ea1cef0d7",
+// "D0106A4D63BD22BEAB9CBA8F41219661",
+// "Aa12345678@",
+// false);
+
+ /**
+ * 模拟盘账户3信息
+ * 存储了模拟盘交易所需的API密钥、秘钥和通过码
+ */
+// OKX_UAT3("0769b50c-2c36-4310-8bd9-cad6bc6c9d8f",
+// "7AF4A574BC44907CE76BBFF91F53852D",
+// "Aa123456@",
+// false);
+
+ // API公钥,用于识别用户身份
+ private String apiKey;
+
+ // API秘钥,用于签名和验证请求
+ private String secretKey;
+
+ // API通过码,用于额外的身份验证
+ private String passphrase;
+
+ // 账户类型,true表示实盘账户,false表示模拟账户
+ private boolean accountType;
+
+ /**
+ * 构造方法
+ *
+ * @param apiKey API公钥,用于识别用户身份
+ * @param secretKey API秘钥,用于签名和验证请求
+ * @param passphrase API通过码,用于额外的身份验证
+ * @param accountType 账户类型,true表示实盘账户,false表示模拟账户
+ */
+ ExchangeInfoEnum(String apiKey, String secretKey, String passphrase, boolean accountType) {
+ this.apiKey = apiKey;
+ this.secretKey = secretKey;
+ this.passphrase = passphrase;
+ this.accountType = accountType;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OKX_QUANT_DOCUMENTATION.md b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OKX_QUANT_DOCUMENTATION.md
deleted file mode 100644
index bce4319..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OKX_QUANT_DOCUMENTATION.md
+++ /dev/null
@@ -1,333 +0,0 @@
-# OKX 量化交易系统文档
-
-## 1. 包结构概述
-
-```
-com.xcong.excoin.modules.okxNewPrice/
-├── celue/ # 策略实现模块
-│ ├── CaoZuoService.java # 策略接口
-│ └── CaoZuoServiceImpl.java # 策略实现类
-├── jiaoyi/ # 交易相关模块
-├── okxWs/ # OKX WebSocket 相关类
-│ ├── enums/ # WebSocket 相关枚举
-│ ├── param/ # WebSocket 请求参数
-│ ├── wanggeList/ # 网格列表管理
-│ ├── AccountWs.java # 账户信息处理
-│ ├── BalanceAndPositionWs.java # 余额和持仓处理
-│ ├── InstrumentsWs.java # 合约信息处理
-│ ├── LoginWs.java # 登录处理
-│ ├── OrderInfoWs.java # 订单信息处理
-│ ├── PositionsWs.java # 持仓信息处理
-│ └── TradeOrderWs.java # 交易订单处理
-├── okxpi/ # OKX API 接口封装
-├── utils/ # 工具类
-├── wangge/ # 网格相关模块
-├── zhanghu/ # 账户相关模块
-├── OkxNewPriceWebSocketClient.java # 价格 WebSocket 客户端
-├── OkxQuantWebSocketClient.java # 量化交易 WebSocket 客户端
-├── OkxWebSocketClientManager.java # WebSocket 客户端管理器
-└── OKX_QUANT_DOCUMENTATION.md # 本文档
-```
-
-## 2. 核心组件说明
-
-### 2.1 WebSocket 客户端管理
-
-#### OkxWebSocketClientManager
-
-**功能**:集中管理多个 OKX WebSocket 客户端实例,包括价格客户端和账号客户端。
-
-**核心属性**:
-- `quantClientMap`: 存储所有账号的 `OkxQuantWebSocketClient` 实例
-- `newPriceClient`: 存储价格数据的 `OkxNewPriceWebSocketClient` 实例
-
-**主要方法**:
-- `init()`: 初始化所有 WebSocket 客户端
-- `destroy()`: 销毁所有 WebSocket 客户端资源
-- `getClient()`: 获取指定账号的 WebSocket 客户端
-- `getAllClients()`: 获取所有账号的 WebSocket 客户端
-
-**使用流程**:
-1. Spring 容器启动时自动调用 `init()` 方法
-2. 初始化 `OkxNewPriceWebSocketClient` 用于获取价格数据
-3. 为每个账号创建 `OkxQuantWebSocketClient` 实例
-4. 所有客户端统一由管理器进行生命周期管理
-
-### 2.2 价格 WebSocket 客户端
-
-#### OkxNewPriceWebSocketClient
-
-**功能**:连接 OKX 公共 WebSocket 接口,实时获取标记价格数据,并触发量化交易操作。
-
-**核心属性**:
-- `webSocketClient`: WebSocket 连接客户端
-- `isConnected/isConnecting/isInitialized`: 连接状态标志
-- `lastMessageTime`: 最后收到消息的时间
-
-**主要方法**:
-- `init()`: 初始化 WebSocket 客户端
-- `destroy()`: 销毁 WebSocket 客户端资源
-- `connect()`: 建立 WebSocket 连接
-- `startHeartbeat()`: 启动心跳检测
-- `processPushData()`: 处理价格推送数据
-- `triggerQuantOperations()`: 触发量化交易操作
-
-**价格处理流程**:
-1. 连接 OKX WebSocket 公共接口
-2. 订阅标记价格通道
-3. 收到价格数据后保存到 Redis
-4. 调用 `triggerQuantOperations()` 触发量化交易
-5. 实现心跳检测和自动重连机制
-
-### 2.3 账号 WebSocket 客户端
-
-#### OkxQuantWebSocketClient
-
-**功能**:连接 OKX 私有 WebSocket 接口,处理账号登录、持仓、订单等私有数据。
-
-**核心属性**:
-- `account`: 账号信息枚举
-- `webSocketClient`: WebSocket 连接客户端
-- `isConnected/isConnecting`: 连接状态标志
-
-**主要方法**:
-- `init()`: 初始化 WebSocket 客户端
-- `destroy()`: 销毁 WebSocket 客户端资源
-- `connect()`: 建立 WebSocket 连接
-- `websocketLogin()`: 账号登录
-- `subscribeChannels()`: 订阅私有通道
-- `processPushData()`: 处理数据推送
-
-**登录与订阅流程**:
-1. 连接 OKX WebSocket 私有接口
-2. 发送登录请求
-3. 登录成功后订阅账户、持仓、订单等通道
-4. 接收并处理私有数据推送
-5. 实现心跳检测和自动重连机制
-
-## 3. 网格策略实现
-
-### 3.1 网格配置
-
-#### WangGeListEnum
-
-**功能**:定义不同价格区间的网格参数,包括价格上下限、方向、步距等。
-
-**核心属性**:
-- `name`: 网格名称
-- `jiage_shangxian`: 价格上限
-- `jiage_xiaxian`: 价格下限
-- `jian_ju`: 网格步距
-- `fang_xiang`: 持仓方向 (long/short)
-- `zhi_sun_dian`: 止损点
-
-**主要方法**:
-- `getGridByPrice()`: 根据当前价格获取对应的网格
-
-**网格定义示例**:
-```java
-UP("上层做空", "2", "3100", "3000", "2", "short", "3100"),
-CENTER("中间做多", "2", "3000", "2900", "2", "long", "2900"),
-CENTER_ONE("中间做空", "2", "2900", "2870", "2", "short", "2870"),
-DOWN("下层做多", "2", "2870", "2850", "2", "long", "2850");
-```
-
-### 3.2 策略实现
-
-#### CaoZuoService/CaoZuoServiceImpl
-
-**功能**:实现量化交易策略逻辑,包括加仓、减仓、止损等操作。
-
-**核心方法**:
-- `caoZuoHandler()`: 主要策略逻辑入口
-- `caoZuoZhiSunEvent()`: 止损事件处理
-- `caoZuoInitEvent()`: 初始化订单处理
-- `chooseEvent()`: 事件选择处理
-- `caoZuoLong()`: 多头策略处理
-- `caoZuoShort()`: 空头策略处理
-
-**策略执行流程**:
-1. 检查账户状态和系统开关
-2. 判断当前价格所在网格
-3. 检查是否需要止损
-4. 检查持仓状态:
- - 无持仓:执行初始化订单
- - 有持仓:根据网格策略决定加仓或减仓
-5. 根据多空方向执行相应策略
-
-### 3.3 订单执行
-
-#### TradeOrderWs
-
-**功能**:构建和发送订单请求到 OKX WebSocket 接口。
-
-**核心方法**:
-- `orderEvent()`: 执行订单事件
-
-**订单执行流程**:
-1. 验证下单参数和账户状态
-2. 检查账户和持仓通道是否就绪
-3. 构建订单请求 JSON
-4. 发送订单到 WebSocket 接口
-5. 更新订单状态和就绪标志
-
-## 4. 系统交互流程
-
-### 4.1 启动流程
-
-```
-[Spring 容器启动] → OkxWebSocketClientManager.init() → 初始化 newPriceClient → 初始化所有 quantClient → 建立 WebSocket 连接
-```
-
-### 4.2 价格触发交易流程
-
-```
-OkxNewPriceWebSocketClient.onMessage() → processPushData() → triggerQuantOperations() → WangGeListEnum.getGridByPrice() →
- 对每个账号执行:
- 1. 检查反向持仓并止损 → caoZuoZhiSunEvent()
- 2. 执行当前网格策略 → caoZuoHandler() → chooseEvent() → caoZuoLong()/caoZuoShort()
- 3. 发送订单 → TradeOrderWs.orderEvent()
-```
-
-### 4.3 订单执行流程
-
-```
-TradeOrderWs.orderEvent() → 验证参数 → 检查就绪状态 → 构建订单JSON → 发送订单 → 更新状态标志
-```
-
-## 5. 数据结构
-
-### 5.1 订单请求参数
-
-#### TradeRequestParam
-
-**功能**:封装交易订单请求参数。
-
-**核心属性**:
-- `accountName`: 账号名称
-- `markPx`: 标记价格
-- `instId`: 合约ID
-- `tdMode`: 交易模式
-- `posSide`: 持仓方向
-- `ordType`: 订单类型
-- `side`: 买卖方向
-- `sz`: 数量
-- `clOrdId`: 客户订单ID
-- `tradeType`: 交易类型
-
-### 5.2 数据存储结构
-
-系统使用双层 Map 结构存储不同账号的数据:
-
-```java
-// 第一层 key 为账号名称,第二层 key 为数据项
-Map<String, Map<String, String>> accountDataMap = new ConcurrentHashMap<>();
-```
-
-主要数据存储类:
-- `AccountWs.ACCOUNTWSMAP`: 账户信息
-- `PositionsWs.POSITIONSWSMAP`: 持仓信息
-- `OrderInfoWs.ORDERINFOWSMAP`: 订单信息
-- `TradeOrderWs.TRADEORDERWSMAP`: 交易订单信息
-
-## 6. 网格策略核心算法
-
-### 6.1 网格匹配算法
-
-```java
-public static WangGeListEnum getGridByPrice(BigDecimal price) {
- for (WangGeListEnum grid : WangGeListEnum.values()) {
- BigDecimal upperLimit = new BigDecimal(grid.jiage_shangxian);
- BigDecimal lowerLimit = new BigDecimal(grid.jiage_xiaxian);
-
- if (upperLimit.compareTo(lowerLimit) > 0) {
- if (price.compareTo(lowerLimit) > 0 && price.compareTo(upperLimit) <= 0) {
- return grid;
- }
- }
- }
- return null;
-}
-```
-
-### 6.2 交易决策算法
-
-```java
-public TradeRequestParam caoZuoHandler(String accountName, String markPx, String posSide) {
- // 1. 检查系统开关和账户状态
- // 2. 判断止损条件
- // 3. 检查保证金和仓位情况
- // 4. 根据持仓数量决定操作类型
- // 5. 返回交易请求参数
-}
-```
-
-## 7. 错误处理与容错机制
-
-### 7.1 WebSocket 连接管理
-- 实现心跳检测机制,定期发送 ping 请求
-- 自动重连机制,连接断开后使用指数退避策略重连
-- 连接状态管理,避免重复连接
-
-### 7.2 订单执行保障
-- 订单参数验证,确保参数完整性
-- 账户和持仓通道就绪检查
-- 订单状态跟踪,避免重复下单
-
-### 7.3 风险控制
-- 止损机制,限制单次交易亏损
-- 保证金检查,避免满仓操作
-- 系统开关,支持紧急暂停交易
-
-## 8. 扩展与定制
-
-### 8.1 网格参数配置
-可通过修改 `WangGeListEnum` 枚举值来配置不同的网格参数:
-
-```java
-// 格式:名称, 小数位数, 价格上限, 价格下限, 步距, 方向, 止损点
-NEW_GRID("新网格", "2", "4000", "3500", "5", "long", "3500")
-```
-
-### 8.2 策略扩展
-可通过实现 `CaoZuoService` 接口来扩展新的交易策略:
-
-```java
-public class CustomCaoZuoServiceImpl implements CaoZuoService {
- // 实现自定义策略逻辑
-}
-```
-
-### 8.3 多账号支持
-系统天然支持多账号管理,只需在 `ExchangeInfoEnum` 中添加新的账号配置即可。
-
-## 9. 性能优化
-
-1. **并发处理**:使用 `ConcurrentHashMap` 存储账号数据,支持高并发访问
-2. **线程管理**:使用线程池处理异步任务,避免线程泄漏
-3. **连接复用**:多个账号共享相同的 WebSocket 连接参数,减少连接开销
-4. **数据缓存**:使用 Redis 缓存价格数据,提高数据访问效率
-
-## 10. 监控与日志
-
-系统使用 SLF4J 日志框架,记录关键操作和错误信息:
-
-- WebSocket 连接状态
-- 价格变化和网格匹配
-- 订单执行过程
-- 错误和异常信息
-
-通过日志可以监控系统运行状态和排查问题。
-
-## 11. 总结
-
-OKX 量化交易系统是一个基于 WebSocket 的实时交易系统,实现了多网格策略、自动交易执行和风险控制功能。系统采用模块化设计,各组件职责明确,便于维护和扩展。
-
-核心功能包括:
-- 多网格策略配置和管理
-- 实时价格监控和网格匹配
-- 自动交易决策和执行
-- 多账号管理和统一控制
-- 完善的错误处理和风险控制
-
-系统可以根据市场价格变化自动执行交易策略,实现量化交易的自动化和智能化。
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxConfig.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxConfig.java
new file mode 100644
index 0000000..c473b7b
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxConfig.java
@@ -0,0 +1,182 @@
+package com.xcong.excoin.modules.okxNewPrice;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * OKX 网格交易模块全局配置,策略的唯一参数入口。
+ *
+ * <h3>定位</h3>
+ * 通过 Builder 模式将所有运行参数集中管理,避免策略参数散落在多个类中。
+ * 运行时动态参数(step、gridElements、baseLongTraderParam、baseShortTraderParam)
+ * 由 {@link OkxGridTradeService} 在策略执行过程中写入。
+ *
+ * <h3>参数分类</h3>
+ * <table>
+ * <tr><th>类别</th><th>参数</th><th>用途</th></tr>
+ * <tr><td>认证</td><td>apiKey, secretKey, passphrase</td><td>REST/WS 签名认证</td></tr>
+ * <tr><td>交易标的</td><td>instId, leverage, quantity, ctVal</td><td>合约、杠杆、张数、面值</td></tr>
+ * <tr><td>持仓</td><td>tdMode, posSide</td><td>全仓/逐仓、多/空</td></tr>
+ * <tr><td>网格策略</td><td>gridRate, gridQueueSize, priceScale</td><td>间距比例、队列容量、价格精度</td></tr>
+ * <tr><td>止盈止损</td><td>expectedProfit, maxLoss</td><td>整体止盈/亏损阈值(USDT),触发后策略重置</td></tr>
+ * <tr><td>风控</td><td>marginRatioLimit</td><td>保证金占比上限</td></tr>
+ * <tr><td>运行时</td><td>step, gridElements, baseLongTraderParam, baseShortTraderParam</td><td>由策略动态填充</td></tr>
+ * </table>
+ *
+ * @author Administrator
+ */
+public class OkxConfig {
+
+ /** OKX API 密钥 */
+ private final String apiKey;
+ /** OKX API 签名密钥 */
+ private final String secretKey;
+ /** OKX API 密码短语 */
+ private final String passphrase;
+ /** 合约名称(如 ETH-USDT-SWAP) */
+ private final String instId;
+ /** 杠杆倍数 */
+ private final String leverage;
+ /** 保证金模式(cross / isolated) */
+ private final String tdMode;
+ /** 持仓方向(long / short),仅用于网格策略中的方向判定 */
+ private final String posSide;
+ /** 网格间距比例(如 0.0025 表示 0.25%) */
+ private final BigDecimal gridRate;
+ /** 预期收益(USDT),达到后自动重置策略 */
+ private final BigDecimal expectedProfit;
+ /** 最大亏损阈值(USDT) */
+ private final BigDecimal maxLoss;
+ /** 每次下单张数 */
+ private final String quantity;
+ /** 基底开仓张数(初始化时多空各开的张数) */
+ private final String baseQuantity;
+ /** 是否为模拟盘 */
+ private final boolean isSimulate;
+ /** 网格队列容量 */
+ private final int gridQueueSize;
+ /** 保证金占初始本金比例上限 */
+ private final BigDecimal marginRatioLimit;
+ /** 合约面值(单张合约代表的基础资产数量,如 ETH=0.1, BTC=0.01) */
+ private final BigDecimal ctVal;
+ /** 价格精度(交易所价格的最小小数位数,如 1=0.1精度,2=0.01精度) */
+ private final int priceScale;
+
+ /** 网格绝对步长(shortBaseEntryPrice × gridRate),运行时由队列生成逻辑设置 */
+ private BigDecimal step;
+ /** 网格元素列表,由队列初始化时同步填充 */
+ private volatile List<OkxGridElement> gridElements = new ArrayList<>();
+ /** 基座多头挂单参数,在基座成交后填充 */
+ private OkxTraderParam baseLongTraderParam;
+ /** 基座空头挂单参数,在基座成交后填充 */
+ private OkxTraderParam baseShortTraderParam;
+
+ private OkxConfig(Builder builder) {
+ this.apiKey = builder.apiKey;
+ this.secretKey = builder.secretKey;
+ this.passphrase = builder.passphrase;
+ this.instId = builder.instId;
+ this.leverage = builder.leverage;
+ this.tdMode = builder.tdMode;
+ this.posSide = builder.posSide;
+ this.gridRate = builder.gridRate;
+ this.expectedProfit = builder.expectedProfit;
+ this.maxLoss = builder.maxLoss;
+ this.quantity = builder.quantity;
+ this.baseQuantity = builder.baseQuantity;
+ this.isSimulate = builder.isSimulate;
+ this.gridQueueSize = builder.gridQueueSize;
+ this.marginRatioLimit = builder.marginRatioLimit;
+ this.ctVal = builder.ctVal;
+ this.priceScale = builder.priceScale;
+ }
+
+ // ==================== 认证信息 ====================
+ public String getApiKey() { return apiKey; }
+ public String getSecretKey() { return secretKey; }
+ public String getPassphrase() { return passphrase; }
+
+ // ==================== 交易标的 ====================
+ public String getInstId() { return instId; }
+ public String getLeverage() { return leverage; }
+ public String getTdMode() { return tdMode; }
+ public String getPosSide() { return posSide; }
+
+ // ==================== 策略参数 ====================
+ public BigDecimal getGridRate() { return gridRate; }
+ public BigDecimal getExpectedProfit() { return expectedProfit; }
+ public BigDecimal getMaxLoss() { return maxLoss; }
+ public String getQuantity() { return quantity; }
+ public String getBaseQuantity() { return baseQuantity; }
+ public int getGridQueueSize() { return gridQueueSize; }
+
+ // ==================== 风控 ====================
+ public BigDecimal getMarginRatioLimit() { return marginRatioLimit; }
+ public BigDecimal getCtVal() { return ctVal; }
+ public int getPriceScale() { return priceScale; }
+
+ // ==================== 环境 ====================
+ public boolean isSimulate() { return isSimulate; }
+
+ // ==================== 运行时参数 ====================
+ public BigDecimal getStep() { return step; }
+ public void setStep(BigDecimal step) { this.step = step; }
+
+ public List<OkxGridElement> getGridElements() { return gridElements; }
+ public void setGridElements(List<OkxGridElement> gridElements) {
+ this.gridElements = gridElements;
+ OkxGridElement.rebuildIndex(gridElements);
+ }
+
+ public OkxTraderParam getBaseLongTraderParam() { return baseLongTraderParam; }
+ public void setBaseLongTraderParam(OkxTraderParam baseLongTraderParam) { this.baseLongTraderParam = baseLongTraderParam; }
+ public OkxTraderParam getBaseShortTraderParam() { return baseShortTraderParam; }
+ public void setBaseShortTraderParam(OkxTraderParam baseShortTraderParam) { this.baseShortTraderParam = baseShortTraderParam; }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String apiKey;
+ private String secretKey;
+ private String passphrase;
+ private String instId = "ETH-USDT-SWAP";
+ private String leverage = "100";
+ private String tdMode = "cross";
+ private String posSide = "long";
+ private BigDecimal gridRate = new BigDecimal("0.0025");
+ private BigDecimal expectedProfit = new BigDecimal("2");
+ private BigDecimal maxLoss = new BigDecimal("15");
+ private String quantity = "1";
+ private String baseQuantity = "10";
+ private boolean isSimulate = false;
+ private int gridQueueSize = 300;
+ private BigDecimal marginRatioLimit = new BigDecimal("0.2");
+ private BigDecimal ctVal = new BigDecimal("0.1");
+ private int priceScale = 2;
+
+ public Builder apiKey(String apiKey) { this.apiKey = apiKey; return this; }
+ public Builder secretKey(String secretKey) { this.secretKey = secretKey; return this; }
+ public Builder passphrase(String passphrase) { this.passphrase = passphrase; return this; }
+ public Builder instId(String instId) { this.instId = instId; return this; }
+ public Builder leverage(String leverage) { this.leverage = leverage; return this; }
+ public Builder tdMode(String tdMode) { this.tdMode = tdMode; return this; }
+ public Builder posSide(String posSide) { this.posSide = posSide; return this; }
+ public Builder gridRate(BigDecimal gridRate) { this.gridRate = gridRate; return this; }
+ public Builder expectedProfit(BigDecimal expectedProfit) { this.expectedProfit = expectedProfit; return this; }
+ public Builder maxLoss(BigDecimal maxLoss) { this.maxLoss = maxLoss; return this; }
+ public Builder quantity(String quantity) { this.quantity = quantity; return this; }
+ public Builder baseQuantity(String baseQuantity) { this.baseQuantity = baseQuantity; return this; }
+ public Builder isSimulate(boolean isSimulate) { this.isSimulate = isSimulate; return this; }
+ public Builder gridQueueSize(int gridQueueSize) { this.gridQueueSize = gridQueueSize; return this; }
+ public Builder marginRatioLimit(BigDecimal marginRatioLimit) { this.marginRatioLimit = marginRatioLimit; return this; }
+ public Builder ctVal(BigDecimal ctVal) { this.ctVal = ctVal; return this; }
+ public Builder priceScale(int priceScale) { this.priceScale = priceScale; return this; }
+
+ public OkxConfig build() {
+ return new OkxConfig(this);
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridElement.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridElement.java
new file mode 100644
index 0000000..26759c0
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridElement.java
@@ -0,0 +1,293 @@
+package com.xcong.excoin.modules.okxNewPrice;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 网格价格层级,策略的最小操作单元。
+ *
+ * <h3>定位</h3>
+ * 每个 OkxGridElement 对应网格中的一个价格点,同时持有该点的多仓和空仓挂单状态。
+ * 维护全局静态 HashMap 索引实现 O(1) 双向查询。
+ *
+ * <h3>ID 体系与链表</h3>
+ * <pre>
+ * ID ≦ -1: 空仓队列区域(降序),ID 自减,gridPrice 递减
+ * ID = 0: 基座位置,gridPrice = shortBaseEntryPrice
+ * ID ≧ 1: 多仓队列区域(升序),ID 自增,gridPrice 递增
+ *
+ * 链表: ... ← -3 ← -2 ← -1 ← 0 → 1 → 2 → 3 → ...
+ * </pre>
+ *
+ * <h3>8 个全局 O(1) 索引</h3>
+ * <pre>
+ * INDEX → findById(int) ID → 元素
+ * PRICE_INDEX → findByPrice(BigDecimal) 价格 → 元素
+ * LONG_ORDER_ID_INDEX → findByLongOrderId(String) 多仓挂单ID → 元素
+ * SHORT_ORDER_ID_INDEX → findByShortOrderId(String) 空仓挂单ID → 元素
+ * LONG_TP_ORDER_ID_INDEX→ findByLongTakeProfitOrderId(String) 多止盈ID → 元素
+ * SHORT_TP_ORDER_ID_INDEX→ findByShortTakeProfitOrderId(String) 空止盈ID → 元素
+ * LONG_SL_ORDER_ID_INDEX→ findByLongStopLossOrderId(String) 多止损ID → 元素
+ * SHORT_SL_ORDER_ID_INDEX→ findByShortStopLossOrderId(String) 空止损ID → 元素
+ * </pre>
+ *
+ * @author Administrator
+ */
+public class OkxGridElement {
+
+ private int id;
+ private BigDecimal gridPrice;
+ private boolean hasLongOrder;
+ private boolean hasShortOrder;
+ private OkxTraderParam longTraderParam;
+ private OkxTraderParam shortTraderParam;
+ private Integer upId;
+ private Integer downId;
+ private String longOrderId;
+ private String shortOrderId;
+ private String longTakeProfitOrderId;
+ private String shortTakeProfitOrderId;
+ private String longStopLossOrderId;
+ private String shortStopLossOrderId;
+
+ // ==================== 全局索引 ====================
+ private static final Map<Integer, OkxGridElement> INDEX = new ConcurrentHashMap<>();
+ private static final Map<BigDecimal, OkxGridElement> PRICE_INDEX = new ConcurrentHashMap<>();
+ private static final Map<String, OkxGridElement> LONG_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+ private static final Map<String, OkxGridElement> SHORT_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+ private static final Map<String, OkxGridElement> LONG_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+ private static final Map<String, OkxGridElement> SHORT_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+ private static final Map<String, OkxGridElement> LONG_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+ private static final Map<String, OkxGridElement> SHORT_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+
+ // ==================== 静态查找方法 ====================
+
+ public static OkxGridElement findById(int id) {
+ return INDEX.get(id);
+ }
+
+ public static OkxGridElement findByPrice(BigDecimal price) {
+ return PRICE_INDEX.get(price);
+ }
+
+ public static OkxGridElement findByLongOrderId(String orderId) {
+ return LONG_ORDER_ID_INDEX.get(orderId);
+ }
+
+ public static OkxGridElement findByShortOrderId(String orderId) {
+ return SHORT_ORDER_ID_INDEX.get(orderId);
+ }
+
+ public static OkxGridElement findByLongTakeProfitOrderId(String orderId) {
+ return LONG_TP_ORDER_ID_INDEX.get(orderId);
+ }
+
+ public static OkxGridElement findByShortTakeProfitOrderId(String orderId) {
+ return SHORT_TP_ORDER_ID_INDEX.get(orderId);
+ }
+
+ public static OkxGridElement findByLongStopLossOrderId(String orderId) {
+ return LONG_SL_ORDER_ID_INDEX.get(orderId);
+ }
+
+ public static OkxGridElement findByShortStopLossOrderId(String orderId) {
+ return SHORT_SL_ORDER_ID_INDEX.get(orderId);
+ }
+
+ /**
+ * 全量重建全局索引。由 OkxConfig.setGridElements() 调用。
+ */
+ public static void rebuildIndex(List<OkxGridElement> elements) {
+ INDEX.clear();
+ PRICE_INDEX.clear();
+ LONG_ORDER_ID_INDEX.clear();
+ SHORT_ORDER_ID_INDEX.clear();
+ LONG_TP_ORDER_ID_INDEX.clear();
+ SHORT_TP_ORDER_ID_INDEX.clear();
+ LONG_SL_ORDER_ID_INDEX.clear();
+ SHORT_SL_ORDER_ID_INDEX.clear();
+ for (OkxGridElement e : elements) {
+ INDEX.put(e.getId(), e);
+ putDynamicIndices(e);
+ }
+ logAll();
+ }
+
+ /**
+ * 增量刷新动态索引。每次修改订单状态后调用。
+ */
+ public static void refreshIndices() {
+ PRICE_INDEX.clear();
+ LONG_ORDER_ID_INDEX.clear();
+ SHORT_ORDER_ID_INDEX.clear();
+ LONG_TP_ORDER_ID_INDEX.clear();
+ SHORT_TP_ORDER_ID_INDEX.clear();
+ LONG_SL_ORDER_ID_INDEX.clear();
+ SHORT_SL_ORDER_ID_INDEX.clear();
+ for (OkxGridElement e : INDEX.values()) {
+ putDynamicIndices(e);
+ }
+ logAll();
+ }
+
+ /**
+ * 获取所有已挂空仓条件单且当前价高于其价格、无止盈单的网格元素。
+ */
+ public static List<OkxGridElement> findAllLongOrders(BigDecimal currentPrice) {
+ List<OkxGridElement> result = new ArrayList<>();
+ for (OkxGridElement e : INDEX.values()) {
+ if (e.isHasLongOrder() && e.getGridPrice().compareTo(currentPrice) > 0 && e.getLongTakeProfitOrderId() == null) {
+ result.add(e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 获取所有已挂多仓条件单且当前价低于其价格、无止盈单的网格元素。
+ */
+ public static List<OkxGridElement> findAllShortOrders(BigDecimal currentPrice) {
+ List<OkxGridElement> result = new ArrayList<>();
+ for (OkxGridElement e : INDEX.values()) {
+ if (e.isHasShortOrder() && e.getGridPrice().compareTo(currentPrice) < 0 && e.getShortTakeProfitOrderId() == null) {
+ result.add(e);
+ }
+ }
+ return result;
+ }
+
+ private static void putDynamicIndices(OkxGridElement e) {
+ PRICE_INDEX.put(e.getGridPrice(), e);
+ if (e.getLongOrderId() != null) LONG_ORDER_ID_INDEX.put(e.getLongOrderId(), e);
+ if (e.getShortOrderId() != null) SHORT_ORDER_ID_INDEX.put(e.getShortOrderId(), e);
+ if (e.getLongTakeProfitOrderId() != null) LONG_TP_ORDER_ID_INDEX.put(e.getLongTakeProfitOrderId(), e);
+ if (e.getShortTakeProfitOrderId() != null) SHORT_TP_ORDER_ID_INDEX.put(e.getShortTakeProfitOrderId(), e);
+ if (e.getLongStopLossOrderId() != null) LONG_SL_ORDER_ID_INDEX.put(e.getLongStopLossOrderId(), e);
+ if (e.getShortStopLossOrderId() != null) SHORT_SL_ORDER_ID_INDEX.put(e.getShortStopLossOrderId(), e);
+ }
+
+ public static void logAll() {
+ List<OkxGridElement> sorted = new ArrayList<>(INDEX.values());
+ sorted.sort((a, b) -> Integer.compare(a.getId(), b.getId()));
+ StringBuilder sb = new StringBuilder("\n========== OKX 网格数据 ==========\n");
+ for (OkxGridElement e : sorted) {
+ if (e.isHasLongOrder() || e.isHasShortOrder()
+ || e.getLongStopLossOrderId() != null || e.getShortStopLossOrderId() != null) {
+ sb.append(String.format(
+ " ID=%4d 价格=%s up=%s down=%s 多仓=%s(%s) 空仓=%s(%s) 多止盈=%s 空止盈=%s 多止损=%s 空止损=%s\n",
+ e.getId(), e.getGridPrice(), e.getUpId(), e.getDownId(),
+ e.isHasLongOrder() ? "有" : "无", e.getLongOrderId() != null ? e.getLongOrderId() : "-",
+ e.isHasShortOrder() ? "有" : "无", e.getShortOrderId() != null ? e.getShortOrderId() : "-",
+ e.getLongTakeProfitOrderId() != null ? e.getLongTakeProfitOrderId() : "-",
+ e.getShortTakeProfitOrderId() != null ? e.getShortTakeProfitOrderId() : "-",
+ e.getLongStopLossOrderId() != null ? e.getLongStopLossOrderId() : "-",
+ e.getShortStopLossOrderId() != null ? e.getShortStopLossOrderId() : "-"));
+ }
+ }
+ sb.append(String.format(
+ " 索引统计: ID=%d 价格=%d 多仓订单ID=%d 空仓订单ID=%d 多止盈ID=%d 空止盈ID=%d 多止损ID=%d 空止损ID=%d\n",
+ INDEX.size(), PRICE_INDEX.size(), LONG_ORDER_ID_INDEX.size(), SHORT_ORDER_ID_INDEX.size(),
+ LONG_TP_ORDER_ID_INDEX.size(), SHORT_TP_ORDER_ID_INDEX.size(),
+ LONG_SL_ORDER_ID_INDEX.size(), SHORT_SL_ORDER_ID_INDEX.size()));
+ sb.append("================================\n");
+ System.out.println(sb);
+ }
+
+ public OkxGridElement getUp() {
+ return upId != null ? INDEX.get(upId) : null;
+ }
+
+ public OkxGridElement getDown() {
+ return downId != null ? INDEX.get(downId) : null;
+ }
+
+ private OkxGridElement(Builder builder) {
+ this.id = builder.id;
+ this.gridPrice = builder.gridPrice;
+ this.hasLongOrder = builder.hasLongOrder;
+ this.hasShortOrder = builder.hasShortOrder;
+ this.longTraderParam = builder.longTraderParam;
+ this.shortTraderParam = builder.shortTraderParam;
+ this.upId = builder.upId;
+ this.downId = builder.downId;
+ this.longOrderId = builder.longOrderId;
+ this.shortOrderId = builder.shortOrderId;
+ this.longTakeProfitOrderId = builder.longTakeProfitOrderId;
+ this.shortTakeProfitOrderId = builder.shortTakeProfitOrderId;
+ this.longStopLossOrderId = builder.longStopLossOrderId;
+ this.shortStopLossOrderId = builder.shortStopLossOrderId;
+ }
+
+ // ==================== getters/setters ====================
+ public int getId() { return id; }
+ public void setId(int id) { this.id = id; }
+ public BigDecimal getGridPrice() { return gridPrice; }
+ public void setGridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; }
+ public boolean isHasLongOrder() { return hasLongOrder; }
+ public void setHasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; }
+ public boolean isHasShortOrder() { return hasShortOrder; }
+ public void setHasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; }
+ public OkxTraderParam getLongTraderParam() { return longTraderParam; }
+ public void setLongTraderParam(OkxTraderParam longTraderParam) { this.longTraderParam = longTraderParam; }
+ public OkxTraderParam getShortTraderParam() { return shortTraderParam; }
+ public void setShortTraderParam(OkxTraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; }
+ public Integer getUpId() { return upId; }
+ public void setUpId(Integer upId) { this.upId = upId; }
+ public Integer getDownId() { return downId; }
+ public void setDownId(Integer downId) { this.downId = downId; }
+ public String getLongOrderId() { return longOrderId; }
+ public void setLongOrderId(String longOrderId) { this.longOrderId = longOrderId; }
+ public String getShortOrderId() { return shortOrderId; }
+ public void setShortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; }
+ public String getLongTakeProfitOrderId() { return longTakeProfitOrderId; }
+ public void setLongTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; }
+ public String getShortTakeProfitOrderId() { return shortTakeProfitOrderId; }
+ public void setShortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; }
+ public String getLongStopLossOrderId() { return longStopLossOrderId; }
+ public void setLongStopLossOrderId(String longStopLossOrderId) { this.longStopLossOrderId = longStopLossOrderId; }
+ public String getShortStopLossOrderId() { return shortStopLossOrderId; }
+ public void setShortStopLossOrderId(String shortStopLossOrderId) { this.shortStopLossOrderId = shortStopLossOrderId; }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private int id;
+ private BigDecimal gridPrice;
+ private boolean hasLongOrder = false;
+ private boolean hasShortOrder = false;
+ private OkxTraderParam longTraderParam;
+ private OkxTraderParam shortTraderParam;
+ private Integer upId;
+ private Integer downId;
+ private String longOrderId;
+ private String shortOrderId;
+ private String longTakeProfitOrderId;
+ private String shortTakeProfitOrderId;
+ private String longStopLossOrderId;
+ private String shortStopLossOrderId;
+
+ public Builder id(int id) { this.id = id; return this; }
+ public Builder gridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; return this; }
+ public Builder hasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; return this; }
+ public Builder hasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; return this; }
+ public Builder longTraderParam(OkxTraderParam longTraderParam) { this.longTraderParam = longTraderParam; return this; }
+ public Builder shortTraderParam(OkxTraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; return this; }
+ public Builder upId(Integer upId) { this.upId = upId; return this; }
+ public Builder downId(Integer downId) { this.downId = downId; return this; }
+ public Builder longOrderId(String longOrderId) { this.longOrderId = longOrderId; return this; }
+ public Builder shortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; return this; }
+ public Builder longTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; return this; }
+ public Builder shortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; return this; }
+ public Builder longStopLossOrderId(String longStopLossOrderId) { this.longStopLossOrderId = longStopLossOrderId; return this; }
+ public Builder shortStopLossOrderId(String shortStopLossOrderId) { this.shortStopLossOrderId = shortStopLossOrderId; return this; }
+
+ public OkxGridElement build() {
+ return new OkxGridElement(this);
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
new file mode 100644
index 0000000..1a7cb5c
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
@@ -0,0 +1,760 @@
+package com.xcong.excoin.modules.okxNewPrice;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OKXContants;
+import com.xcong.excoin.utils.dingtalk.DingTalkUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+
+/**
+ * OKX 网格交易策略引擎 — 多空对冲网格。
+ *
+ * <h3>策略原理</h3>
+ * 对齐 Gate 版本逻辑:以空仓基底入场价为价格基准,向上/向下各生成价格网格队列。
+ * 价格触发网格层级时挂条件单,成交后自动挂止盈单。
+ *
+ * <h3>完整生命周期</h3>
+ * <pre>
+ * startGrid() → WAITING_KLINE
+ * ↓
+ * onKline(首根K线) → OPENING → 异步市价双开基底(开多+开空)
+ * ↓
+ * onPositionUpdate() → 基底成交 → baseLongOpened && baseShortOpened
+ * ↓
+ * tryGenerateQueues() → generateShortQueue()+generateLongQueue()+updateGridElements()
+ * → 挂基座止损单 + state=ACTIVE
+ * ↓
+ * ACTIVE 状态每根K线:
+ * processShortGrid() + processLongGrid() → 匹配队列 → 挂条件单 → 订单成交后挂止盈
+ * ↓
+ * onPositionClose() → cumulativePnl 累加 → 检查停止条件
+ * </pre>
+ *
+ * <h3>OKX vs Gate 差异</h3>
+ * <ul>
+ * <li>OKX 使用 side(buy/sell)+posSide(long/short) 下单,而非 size 正负</li>
+ * <li>条件单使用 algo order (ordType=conditional)</li>
+ * <li>止盈止损通过 algo order 实现</li>
+ * </ul>
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class OkxGridTradeService {
+
+ public enum StrategyState {
+ WAITING_KLINE, OPENING, ACTIVE, STOPPED
+ }
+
+ private final OkxConfig config;
+ private final OkxTradeExecutor executor;
+ private final OKXAccount okxAccount;
+
+ private volatile StrategyState state = StrategyState.WAITING_KLINE;
+
+ /** 空仓价格队列,降序排列(大→小) */
+ private final List<BigDecimal> shortPriceQueue = Collections.synchronizedList(new ArrayList<>());
+ /** 多仓价格队列,升序排列(小→大) */
+ private final List<BigDecimal> longPriceQueue = Collections.synchronizedList(new ArrayList<>());
+
+ /** 当前多仓条件单映射:algoId → 止盈价格 */
+ private final Map<String, BigDecimal> currentLongOrderIds = Collections.synchronizedMap(new LinkedHashMap<>());
+ /** 当前空仓条件单映射:algoId → 止盈价格 */
+ private final Map<String, BigDecimal> currentShortOrderIds = Collections.synchronizedMap(new LinkedHashMap<>());
+
+ /** 基底空头入场价 */
+ private BigDecimal shortBaseEntryPrice;
+ /** 基底多头入场价 */
+ private BigDecimal longBaseEntryPrice;
+ /** 基底多头是否已开 */
+ private volatile boolean baseLongOpened = false;
+ /** 基底空头是否已开 */
+ private volatile boolean baseShortOpened = false;
+
+ private volatile boolean shortActive = false;
+ private volatile boolean longActive = false;
+
+ private volatile BigDecimal lastKlinePrice;
+ private volatile BigDecimal cumulativePnl = BigDecimal.ZERO;
+ private volatile BigDecimal unrealizedPnl = BigDecimal.ZERO;
+ private volatile BigDecimal longEntryPrice = BigDecimal.ZERO;
+ private volatile BigDecimal shortEntryPrice = BigDecimal.ZERO;
+ private volatile BigDecimal longPositionSize = BigDecimal.ZERO;
+ private volatile BigDecimal shortPositionSize = BigDecimal.ZERO;
+ private volatile BigDecimal initialPrincipal = BigDecimal.ZERO;
+
+ public OkxGridTradeService(OkxConfig config, OKXAccount okxAccount) {
+ this.config = config;
+ this.okxAccount = okxAccount;
+ this.executor = new OkxTradeExecutor(okxAccount, config.getInstId(), config.getTdMode());
+ }
+
+ // ---- 初始化 ----
+
+ /**
+ * 初始化策略环境:获取账户 → 清旧条件单 → 平已有仓位 → 设杠杆。
+ */
+ public void init() {
+ try {
+ // 1. 查询账户获取初始本金
+ String balanceResp = executor.getBalance();
+ if (balanceResp != null) {
+ JSONObject json = JSON.parseObject(balanceResp);
+ if ("0".equals(json.getString("code"))) {
+ JSONArray data = json.getJSONArray("data");
+ if (data != null && !data.isEmpty()) {
+ JSONObject detail = data.getJSONObject(0);
+ String totalEq = detail.getString("totalEq");
+ if (totalEq != null) {
+ this.initialPrincipal = new BigDecimal(totalEq);
+ log.info("[OKX] 初始本金: {} USDT", initialPrincipal);
+ }
+ }
+ }
+ }
+
+ // 2. 清除旧条件单
+ executor.cancelAllAlgoOrders();
+ log.info("[OKX] 旧条件单已清除");
+
+ // 3. 平掉已有仓位
+ closeExistingPositions();
+
+ // 4. 设置杠杆
+ executor.setLeverage(config.getLeverage());
+
+ log.info("[OKX] 初始化完成, 合约:{}, 杠杆:{}x", config.getInstId(), config.getLeverage());
+ } catch (Exception e) {
+ log.error("[OKX] 初始化失败", e);
+ }
+ }
+
+ /**
+ * 平掉当前合约的所有已有仓位。
+ */
+ private void closeExistingPositions() {
+ try {
+ String posResp = executor.getPositions();
+ if (posResp == null) return;
+ JSONObject json = JSON.parseObject(posResp);
+ if (!"0".equals(json.getString("code"))) return;
+ JSONArray data = json.getJSONArray("data");
+ if (data == null || data.isEmpty()) {
+ log.info("[OKX] 无已有仓位");
+ return;
+ }
+ for (int i = 0; i < data.size(); i++) {
+ JSONObject pos = data.getJSONObject(i);
+ String instId = pos.getString("instId");
+ if (!config.getInstId().equals(instId)) continue;
+ String posSide = pos.getString("posSide");
+ String posSz = pos.getString("pos");
+ if (posSz == null || "0".equals(posSz)) continue;
+
+ String side = "long".equals(posSide) ? "sell" : "buy";
+ executor.marketClose(side, posSide, posSz);
+ log.info("[OKX] 平已有仓位, posSide:{}, sz:{}, side:{}", posSide, posSz, side);
+ }
+ } catch (Exception e) {
+ log.warn("[OKX] 平仓位异常", e);
+ }
+ }
+
+ // ---- 启动/停止 ----
+
+ public void startGrid() {
+ if (state != StrategyState.WAITING_KLINE && state != StrategyState.STOPPED) {
+ log.warn("[OKX] 策略已在运行中, state:{}", state);
+ return;
+ }
+ state = StrategyState.WAITING_KLINE;
+ cumulativePnl = BigDecimal.ZERO;
+ unrealizedPnl = BigDecimal.ZERO;
+ longEntryPrice = BigDecimal.ZERO;
+ shortEntryPrice = BigDecimal.ZERO;
+ longPositionSize = BigDecimal.ZERO;
+ shortPositionSize = BigDecimal.ZERO;
+ baseLongOpened = false;
+ baseShortOpened = false;
+ longActive = false;
+ shortActive = false;
+ shortPriceQueue.clear();
+ longPriceQueue.clear();
+ currentLongOrderIds.clear();
+ currentShortOrderIds.clear();
+ log.info("[OKX] 网格策略已启动");
+ }
+
+ public void stopGrid() {
+ state = StrategyState.STOPPED;
+ executor.cancelAllAlgoOrders();
+ executor.shutdown();
+ log.info("[OKX] 策略已停止, 累计盈亏: {}", cumulativePnl);
+ }
+
+ // ---- K线回调 ----
+
+ public void onKline(BigDecimal closePrice) {
+ lastKlinePrice = closePrice;
+ updateUnrealizedPnl();
+
+ if (state == StrategyState.STOPPED) {
+ executor.cancelAllAlgoOrders();
+ closeExistingPositions();
+ BigDecimal totalPnl = cumulativePnl.add(unrealizedPnl);
+ log.info("[OKX] 已实现:{}, 未实现:{}, 合计:{}", cumulativePnl, unrealizedPnl, totalPnl);
+ startGrid();
+ return;
+ }
+
+ if (state == StrategyState.WAITING_KLINE) {
+ state = StrategyState.OPENING;
+ log.info("[OKX] 首根K线到达,开基底仓位 多空各{}张...", config.getBaseQuantity());
+ executor.openLong(config.getBaseQuantity(), (orderId) -> {
+ OkxTraderParam baseLongTp = OkxTraderParam.builder().entryOrderId(orderId).build();
+ config.setBaseLongTraderParam(baseLongTp);
+ }, null);
+ executor.openShort(config.getBaseQuantity(), (orderId) -> {
+ OkxTraderParam baseShortTp = OkxTraderParam.builder().entryOrderId(orderId).build();
+ config.setBaseShortTraderParam(baseShortTp);
+ }, null);
+ return;
+ }
+
+ if (state != StrategyState.ACTIVE) {
+ return;
+ }
+ checkProfitAndReset();
+ }
+
+ // ---- 仓位推送回调 ----
+
+ public void onPositionUpdate(String instId, String posSide, BigDecimal posSize, BigDecimal avgPx) {
+ if (state == StrategyState.STOPPED || state == StrategyState.WAITING_KLINE) {
+ return;
+ }
+
+ boolean hasPosition = posSize.compareTo(BigDecimal.ZERO) > 0;
+
+ if ("long".equals(posSide)) {
+ if (hasPosition) {
+ longActive = true;
+ longEntryPrice = avgPx;
+ if (!baseLongOpened) {
+ longPositionSize = posSize;
+ longBaseEntryPrice = avgPx;
+ baseLongOpened = true;
+ log.info("[OKX] 基底多成交价: {}", longBaseEntryPrice);
+ tryGenerateQueues();
+ } else {
+ longPositionSize = posSize;
+ }
+ } else {
+ if (longActive && state == StrategyState.ACTIVE) {
+ log.info("[OKX] 多仓持仓归零,重置策略");
+ handlePositionZeroAndReset("多仓");
+ }
+ longActive = false;
+ longPositionSize = BigDecimal.ZERO;
+ }
+ } else if ("short".equals(posSide)) {
+ if (hasPosition) {
+ shortActive = true;
+ shortEntryPrice = avgPx;
+ if (!baseShortOpened) {
+ shortPositionSize = posSize;
+ shortBaseEntryPrice = avgPx;
+ baseShortOpened = true;
+ log.info("[OKX] 基底空成交价: {}", shortBaseEntryPrice);
+ tryGenerateQueues();
+ } else {
+ shortPositionSize = posSize;
+ }
+ } else {
+ if (shortActive && state == StrategyState.ACTIVE) {
+ log.info("[OKX] 空仓持仓归零,重置策略");
+ handlePositionZeroAndReset("空仓");
+ }
+ shortActive = false;
+ shortPositionSize = BigDecimal.ZERO;
+ }
+ }
+ }
+
+ // ---- 平仓推送回调 ----
+
+ public void onPositionClose(String side, BigDecimal pnl) {
+ if (state == StrategyState.STOPPED) {
+ return;
+ }
+ cumulativePnl = cumulativePnl.add(pnl);
+ updateUnrealizedPnl();
+ BigDecimal totalPnl = cumulativePnl.add(unrealizedPnl);
+ log.info("[OKX] 已实现:{}, 未实现:{}, 合计:{}", cumulativePnl, unrealizedPnl, totalPnl);
+ if (totalPnl.compareTo(config.getMaxLoss().negate()) <= 0) {
+ String logMsg = StrUtil.format("[OKX] 已达亏损风险值(合计{}), 已实现:{}, 未实现:{}",
+ totalPnl, cumulativePnl, unrealizedPnl);
+ log.info(logMsg);
+ DingTalkUtils.getDefault().sendActionCard("风险提醒", logMsg, config.getApiKey(), "");
+ }
+ }
+
+ // ---- 订单/条件单推送回调 ----
+
+ public void onOrderUpdate(String algoId, String state, String ordType) {
+ if (!"effective".equals(state) && !"canceled".equals(state)) {
+ return;
+ }
+
+ // 匹配止损单
+ OkxGridElement byLongStopLoss = OkxGridElement.findByLongStopLossOrderId(algoId);
+ if (byLongStopLoss != null) {
+ handleLongStopLossTriggered(byLongStopLoss);
+ return;
+ }
+ OkxGridElement byShortStopLoss = OkxGridElement.findByShortStopLossOrderId(algoId);
+ if (byShortStopLoss != null) {
+ handleShortStopLossTriggered(byShortStopLoss);
+ return;
+ }
+
+ // 匹配挂单 —— 条件单成交后:清空挂单状态 + 追挂止损 + 挂止盈单
+ OkxGridElement shortGridElement = OkxGridElement.findByShortOrderId(algoId);
+ if (shortGridElement != null && shortGridElement.isHasShortOrder()) {
+ int filledQty = Integer.parseInt(shortGridElement.getShortTraderParam().getQuantity());
+ shortEntryTraderIdParam(shortGridElement, null, false);
+ extendShortStopLoss(filledQty);
+ log.info("[OKX] 空单成交 gridId:{}, qty:{}, 追挂止损", shortGridElement.getId(), filledQty);
+ return;
+ }
+ OkxGridElement longGridElement = OkxGridElement.findByLongOrderId(algoId);
+ if (longGridElement != null && longGridElement.isHasLongOrder()) {
+ int filledQty = Integer.parseInt(longGridElement.getLongTraderParam().getQuantity());
+ longEntryTraderIdParam(longGridElement, null, false);
+ extendLongStopLoss(filledQty);
+ log.info("[OKX] 多单成交 gridId:{}, qty:{}, 追挂止损", longGridElement.getId(), filledQty);
+ return;
+ }
+ }
+
+ // ---- 网格队列处理 ----
+
+ private void tryGenerateQueues() {
+ if (baseLongOpened && baseShortOpened) {
+ generateShortQueue();
+ generateLongQueue();
+ updateGridElements();
+
+ // 标记基座挂单
+ OkxGridElement baseGridElement = OkxGridElement.findById(0);
+ OkxTraderParam baseLongTp = config.getBaseLongTraderParam();
+ baseGridElement.setLongOrderId(baseLongTp.getEntryOrderId());
+ baseGridElement.setHasLongOrder(true);
+ OkxTraderParam baseShortTp = config.getBaseShortTraderParam();
+ baseGridElement.setShortOrderId(baseShortTp.getEntryOrderId());
+ baseGridElement.setHasShortOrder(true);
+
+ // 挂多仓止损 (id=-2 到 -11)
+ for (int id = -2; id >= -11; id--) {
+ OkxGridElement elem = OkxGridElement.findById(id);
+ if (elem == null) continue;
+ BigDecimal triggerPrice = elem.getGridPrice();
+ int finalId = id;
+ executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", "1",
+ profitId -> {
+ elem.setLongStopLossOrderId(profitId);
+ OkxGridElement.refreshIndices();
+ log.info("[OKX] 多仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
+ });
+ }
+
+ // 挂空仓止损 (id=2 到 11)
+ for (int id = 2; id <= 11; id++) {
+ OkxGridElement elem = OkxGridElement.findById(id);
+ if (elem == null) continue;
+ BigDecimal triggerPrice = elem.getGridPrice();
+ int finalId = id;
+ executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", "1",
+ profitId -> {
+ elem.setShortStopLossOrderId(profitId);
+ OkxGridElement.refreshIndices();
+ log.info("[OKX] 空仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
+ });
+ }
+
+ log.info("[OKX] 止损单已全部挂完, 空仓止损: 2~11, 多仓止损: -2~-11");
+ state = StrategyState.ACTIVE;
+ }
+ }
+
+ private void generateShortQueue() {
+ shortPriceQueue.clear();
+ int prec = config.getPriceScale();
+ BigDecimal step = shortBaseEntryPrice.multiply(config.getGridRate()).setScale(prec, RoundingMode.HALF_UP);
+ config.setStep(step);
+ BigDecimal elem = shortBaseEntryPrice.subtract(step).setScale(prec, RoundingMode.HALF_UP);
+ for (int i = 0; i < config.getGridQueueSize(); i++) {
+ shortPriceQueue.add(elem);
+ elem = elem.subtract(step).setScale(prec, RoundingMode.HALF_UP);
+ if (elem.compareTo(BigDecimal.ZERO) <= 0) break;
+ }
+ shortPriceQueue.sort((a, b) -> b.compareTo(a));
+ log.info("[OKX] 空队列:{}", shortPriceQueue);
+ }
+
+ private void generateLongQueue() {
+ longPriceQueue.clear();
+ int prec = config.getPriceScale();
+ BigDecimal step = config.getStep();
+ BigDecimal elem = shortBaseEntryPrice.add(step).setScale(prec, RoundingMode.HALF_UP);
+ for (int i = 0; i < config.getGridQueueSize(); i++) {
+ longPriceQueue.add(elem);
+ elem = elem.add(step).setScale(prec, RoundingMode.HALF_UP);
+ }
+ longPriceQueue.sort(BigDecimal::compareTo);
+ log.info("[OKX] 多队列:{}", longPriceQueue);
+ }
+
+ private void updateGridElements() {
+ List<OkxGridElement> elements = new ArrayList<>();
+ int shortSize = shortPriceQueue.size();
+ int longSize = longPriceQueue.size();
+ int prec = config.getPriceScale();
+ BigDecimal step = config.getStep();
+ String qty = config.getQuantity();
+
+ // 空仓队列: id=-1, -2, ...
+ for (int i = 0; i < shortSize; i++) {
+ int id = -(i + 1);
+ Integer upId = (i == 0) ? 0 : id + 1;
+ Integer downId = (i == shortSize - 1) ? null : id - 1;
+ BigDecimal price = shortPriceQueue.get(i);
+ OkxTraderParam longParam = OkxTraderParam.builder()
+ .direction(OkxTraderParam.Direction.LONG)
+ .entryPrice(price).takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build();
+ OkxTraderParam shortParam = OkxTraderParam.builder()
+ .direction(OkxTraderParam.Direction.SHORT)
+ .entryPrice(price).takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build();
+ elements.add(OkxGridElement.builder().id(id).gridPrice(price).upId(upId).downId(downId)
+ .longTraderParam(longParam).shortTraderParam(shortParam).build());
+ }
+
+ // 位置 0: 基底价格
+ {
+ BigDecimal price = shortBaseEntryPrice;
+ OkxTraderParam longParam = OkxTraderParam.builder()
+ .direction(OkxTraderParam.Direction.LONG)
+ .entryPrice(price).takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build();
+ OkxTraderParam shortParam = OkxTraderParam.builder()
+ .direction(OkxTraderParam.Direction.SHORT)
+ .entryPrice(price).takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build();
+ elements.add(OkxGridElement.builder().id(0).gridPrice(price)
+ .upId(shortSize > 0 ? 1 : null).downId(longSize > 0 ? -1 : null)
+ .longTraderParam(longParam).shortTraderParam(shortParam).build());
+ }
+
+ // 多仓队列: id=1, 2, ...
+ for (int i = 0; i < longSize; i++) {
+ int id = i + 1;
+ Integer downId = (i == 0) ? 0 : id - 1;
+ Integer upId = (i == longSize - 1) ? null : id + 1;
+ BigDecimal price = longPriceQueue.get(i);
+ OkxTraderParam longParam = OkxTraderParam.builder()
+ .direction(OkxTraderParam.Direction.LONG)
+ .entryPrice(price).takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build();
+ OkxTraderParam shortParam = OkxTraderParam.builder()
+ .direction(OkxTraderParam.Direction.SHORT)
+ .entryPrice(price).takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build();
+ elements.add(OkxGridElement.builder().id(id).gridPrice(price).upId(upId).downId(downId)
+ .longTraderParam(longParam).shortTraderParam(shortParam).build());
+ }
+
+ config.setGridElements(elements);
+ log.info("[OKX] 网格元素列表已构建, 共{}个元素", elements.size());
+ }
+
+ // ---- 止损触发处理 ----
+
+ /**
+ * 多仓止损触发处理(Gate 模式逐步缩进)。
+ * 止损触发后向基底方向缩进 1 格挂条件多单,数量 = |触发价 - 当前持仓均价| / 网格步长,取整。
+ * 若 N>2,先取消上一步的旧挂单。
+ */
+ private void handleLongStopLossTriggered(OkxGridElement gridElement) {
+ int gridId = gridElement.getId();
+ int N = Math.abs(gridId);
+ gridElement.setLongStopLossOrderId(null);
+ log.info("[OKX] 多仓止损触发 gridId:{}, 逐步缩进", gridId);
+
+ int newEntryGridId = -(N - 1);
+ OkxGridElement newEntryGrid = OkxGridElement.findById(newEntryGridId);
+ if (newEntryGrid == null) {
+ OkxGridElement.refreshIndices();
+ log.warn("[OKX] 多仓止损触发 gridId:{} 找不到入单网格({})", gridId, newEntryGridId);
+ return;
+ }
+
+ if (N > 2) {
+ int cancelGridId = -(N - 2);
+ OkxGridElement cancelGrid = OkxGridElement.findById(cancelGridId);
+ if (cancelGrid != null && cancelGrid.isHasLongOrder()) {
+ executor.cancelAlgoOrder(cancelGrid.getLongOrderId(), oid -> {
+ longEntryTraderIdParam(cancelGrid, null, false);
+ log.info("[OKX] 多仓止损触发, 取消gridId:{}的多单", cancelGridId);
+ });
+ }
+ }
+
+ BigDecimal triggerPrice = newEntryGrid.getGridPrice();
+ BigDecimal priceDiff = longEntryPrice.subtract(triggerPrice).abs();
+ int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
+ entryQty = Math.max(1, entryQty);
+ String size = String.valueOf(entryQty);
+ log.info("[OKX] 多仓止损触发 gridId:{}, 在gridId:{}挂{}张多单", gridId, newEntryGridId, entryQty);
+ newEntryGrid.getLongTraderParam().setQuantity(size);
+ placeEntryOrderWithPreFlag(newEntryGrid, true, triggerPrice, size);
+ }
+
+ /**
+ * 空仓止损触发处理(Gate 模式逐步缩进)。
+ * 止损触发后向基底方向缩进 1 格挂条件空单,数量 = |触发价 - 当前持仓均价| / 网格步长,取整。
+ * 若 N>2,先取消上一步的旧挂单。
+ */
+ private void handleShortStopLossTriggered(OkxGridElement gridElement) {
+ int gridId = gridElement.getId();
+ int N = gridId;
+ gridElement.setShortStopLossOrderId(null);
+ log.info("[OKX] 空仓止损触发 gridId:{}, 逐步缩进", gridId);
+
+ int newEntryGridId = N - 1;
+ OkxGridElement newEntryGrid = OkxGridElement.findById(newEntryGridId);
+ if (newEntryGrid == null) {
+ OkxGridElement.refreshIndices();
+ log.warn("[OKX] 空仓止损触发 gridId:{} 找不到入单网格({})", gridId, newEntryGridId);
+ return;
+ }
+
+ if (N > 2) {
+ int cancelGridId = N - 2;
+ OkxGridElement cancelGrid = OkxGridElement.findById(cancelGridId);
+ if (cancelGrid != null && cancelGrid.isHasShortOrder()) {
+ executor.cancelAlgoOrder(cancelGrid.getShortOrderId(), oid -> {
+ shortEntryTraderIdParam(cancelGrid, null, false);
+ log.info("[OKX] 空仓止损触发, 取消gridId:{}的空单", cancelGridId);
+ });
+ }
+ }
+
+ BigDecimal triggerPrice = newEntryGrid.getGridPrice();
+ BigDecimal priceDiff = shortEntryPrice.subtract(triggerPrice).abs();
+ int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
+ entryQty = Math.max(1, entryQty);
+ String size = String.valueOf(entryQty);
+ log.info("[OKX] 空仓止损触发 gridId:{}, 在gridId:{}挂{}张空单", gridId, newEntryGridId, entryQty);
+ newEntryGrid.getShortTraderParam().setQuantity(size);
+ placeEntryOrderWithPreFlag(newEntryGrid, false, triggerPrice, size);
+ }
+
+ private void extendLongStopLoss(int filledQty) {
+ int furthestSlId = 0;
+ for (OkxGridElement e : config.getGridElements()) {
+ if (e.getLongStopLossOrderId() != null && e.getId() < furthestSlId) {
+ furthestSlId = e.getId();
+ }
+ }
+ if (furthestSlId == 0) furthestSlId = -11;
+ log.info("[OKX] 多仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
+ for (int i = 0; i < filledQty; i++) {
+ int newSlId = furthestSlId - i - 1;
+ OkxGridElement elem = OkxGridElement.findById(newSlId);
+ if (elem == null) continue;
+ BigDecimal triggerPrice = elem.getGridPrice();
+ int finalSlId = newSlId;
+ executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", "1",
+ profitId -> {
+ elem.setLongStopLossOrderId(profitId);
+ OkxGridElement.refreshIndices();
+ log.info("[OKX] 多仓止损追加, gridId:{}, 触发价:{}, stopLossId:{}", finalSlId, triggerPrice, profitId);
+ });
+ }
+ }
+
+ private void extendShortStopLoss(int filledQty) {
+ int furthestSlId = 0;
+ for (OkxGridElement e : config.getGridElements()) {
+ if (e.getShortStopLossOrderId() != null && e.getId() > furthestSlId) {
+ furthestSlId = e.getId();
+ }
+ }
+ if (furthestSlId == 0) furthestSlId = 11;
+ log.info("[OKX] 空仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
+ for (int i = 0; i < filledQty; i++) {
+ int newSlId = furthestSlId + i + 1;
+ OkxGridElement elem = OkxGridElement.findById(newSlId);
+ if (elem == null) continue;
+ BigDecimal triggerPrice = elem.getGridPrice();
+ int finalSlId = newSlId;
+ executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", "1",
+ profitId -> {
+ elem.setShortStopLossOrderId(profitId);
+ OkxGridElement.refreshIndices();
+ log.info("[OKX] 空仓止损追加, gridId:{}, 触发价:{}, stopLossId:{}", finalSlId, triggerPrice, profitId);
+ });
+ }
+ }
+
+ // ---- 辅助方法 ----
+
+ private void longTakeProfitTraderIdParam(OkxGridElement baseElement, String profitId, boolean flag) {
+ OkxTraderParam tp = baseElement.getLongTraderParam();
+ tp.setTakeProfitOrderId(profitId);
+ tp.setTakeProfitPlaced(flag);
+ baseElement.setLongTakeProfitOrderId(profitId);
+ OkxGridElement.refreshIndices();
+ }
+
+ private void shortTakeProfitTraderIdParam(OkxGridElement baseElement, String profitId, boolean flag) {
+ OkxTraderParam tp = baseElement.getShortTraderParam();
+ tp.setTakeProfitOrderId(profitId);
+ tp.setTakeProfitPlaced(flag);
+ baseElement.setShortTakeProfitOrderId(profitId);
+ OkxGridElement.refreshIndices();
+ }
+
+ private void longEntryTraderIdParam(OkxGridElement baseElement, String entryId, boolean flag) {
+ OkxTraderParam tp = baseElement.getLongTraderParam();
+ tp.setEntryOrderId(entryId);
+ tp.setEntryOrderPlaced(flag);
+ baseElement.setHasLongOrder(flag);
+ baseElement.setLongOrderId(entryId);
+ OkxGridElement.refreshIndices();
+ }
+
+ private void shortEntryTraderIdParam(OkxGridElement baseElement, String entryId, boolean flag) {
+ OkxTraderParam tp = baseElement.getShortTraderParam();
+ tp.setEntryOrderId(entryId);
+ tp.setEntryOrderPlaced(flag);
+ baseElement.setHasShortOrder(flag);
+ baseElement.setShortOrderId(entryId);
+ OkxGridElement.refreshIndices();
+ }
+
+ private void placeEntryOrderWithPreFlag(OkxGridElement gridElement, boolean isLong,
+ BigDecimal triggerPrice, String size) {
+ if (isLong) {
+ gridElement.setHasLongOrder(true);
+ } else {
+ gridElement.setHasShortOrder(true);
+ }
+ String side = isLong ? "buy" : "sell";
+ String posSide = isLong ? "long" : "short";
+ executor.placeConditionalEntryOrder(triggerPrice.toString(), side, posSide, size,
+ orderId -> {
+ if (isLong) {
+ longEntryTraderIdParam(gridElement, orderId, true);
+ } else {
+ shortEntryTraderIdParam(gridElement, orderId, true);
+ }
+ },
+ () -> {
+ if (isLong) {
+ gridElement.setHasLongOrder(false);
+ gridElement.setLongOrderId(null);
+ } else {
+ gridElement.setHasShortOrder(false);
+ gridElement.setShortOrderId(null);
+ }
+ OkxGridElement.refreshIndices();
+ log.warn("[OKX] 条件单创建失败,回滚标志位 gridId:{}, isLong:{}", gridElement.getId(), isLong);
+ }
+ );
+ }
+
+ private void updateUnrealizedPnl() {
+ if (lastKlinePrice == null || lastKlinePrice.compareTo(BigDecimal.ZERO) == 0) return;
+ BigDecimal multiplier = config.getCtVal();
+ BigDecimal longPnl = BigDecimal.ZERO;
+ BigDecimal shortPnl = BigDecimal.ZERO;
+ if (longPositionSize.compareTo(BigDecimal.ZERO) > 0 && longEntryPrice.compareTo(BigDecimal.ZERO) > 0) {
+ longPnl = longPositionSize.multiply(multiplier).multiply(lastKlinePrice.subtract(longEntryPrice));
+ }
+ if (shortPositionSize.compareTo(BigDecimal.ZERO) > 0 && shortEntryPrice.compareTo(BigDecimal.ZERO) > 0) {
+ shortPnl = shortPositionSize.multiply(multiplier).multiply(shortEntryPrice.subtract(lastKlinePrice));
+ }
+ unrealizedPnl = longPnl.add(shortPnl);
+ log.info("[OKX] 未实现盈亏: {}", unrealizedPnl);
+ }
+
+ private boolean isMarginSafe() {
+ try {
+ String balanceResp = executor.getBalance();
+ if (balanceResp == null) return true;
+ JSONObject json = JSON.parseObject(balanceResp);
+ if (!"0".equals(json.getString("code"))) return true;
+ JSONArray data = json.getJSONArray("data");
+ if (data == null || data.isEmpty()) return true;
+ JSONObject detail = data.getJSONObject(0);
+ String imr = detail.getString("imr");
+ if (imr == null) return true;
+ BigDecimal margin = new BigDecimal(imr);
+ if (initialPrincipal.compareTo(BigDecimal.ZERO) == 0) return true;
+ BigDecimal ratio = margin.divide(initialPrincipal, 4, RoundingMode.HALF_UP);
+ log.debug("[OKX] 保证金比例: {}/{}={}", margin, initialPrincipal, ratio);
+ return ratio.compareTo(config.getMarginRatioLimit()) < 0;
+ } catch (Exception e) {
+ log.warn("[OKX] 查保证金失败,默认放行", e);
+ return true;
+ }
+ }
+
+ private void checkProfitAndReset() {
+ try {
+ String balanceResp = executor.getBalance();
+ if (balanceResp == null) return;
+ JSONObject json = JSON.parseObject(balanceResp);
+ if (!"0".equals(json.getString("code"))) return;
+ JSONArray data = json.getJSONArray("data");
+ if (data == null || data.isEmpty()) return;
+ JSONObject detail = data.getJSONObject(0);
+ String upl = detail.getString("upl");
+ String availEq = detail.getString("availEq");
+ if (upl == null || availEq == null) return;
+ BigDecimal unrealisedPnl = new BigDecimal(upl);
+ BigDecimal available = new BigDecimal(availEq);
+ BigDecimal totalEquity = unrealisedPnl.add(available);
+ BigDecimal target = initialPrincipal.add(config.getExpectedProfit());
+ log.info("[OKX] 盈亏检查 upl:{}, availEq:{}, 合计:{}, 目标:{}", unrealisedPnl, available, totalEquity, target);
+ if (totalEquity.compareTo(target) > 0) {
+ log.info("[OKX] 盈亏达标({}>{}),重置策略", totalEquity, target);
+ state = StrategyState.STOPPED;
+ closeExistingPositions();
+ executor.cancelAllAlgoOrders();
+ startGrid();
+ }
+ } catch (Exception e) {
+ log.warn("[OKX] 盈亏检查失败", e);
+ }
+ }
+
+ private void handlePositionZeroAndReset(String direction) {
+ state = StrategyState.STOPPED;
+ executor.cancelAllAlgoOrders();
+ closeExistingPositions();
+ startGrid();
+ }
+
+ // ---- getters ----
+ public BigDecimal getLastKlinePrice() { return lastKlinePrice; }
+ public boolean isStrategyActive() { return state != StrategyState.STOPPED && state != StrategyState.WAITING_KLINE; }
+ public BigDecimal getCumulativePnl() { return cumulativePnl; }
+ public BigDecimal getUnrealizedPnl() { return unrealizedPnl; }
+ public StrategyState getState() { return state; }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java
new file mode 100644
index 0000000..4775dd2
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java
@@ -0,0 +1,282 @@
+package com.xcong.excoin.modules.okxNewPrice;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.modules.okxNewPrice.gridWs.OkxGridChannelHandler;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.SignUtils;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.SSLConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * OKX 网格交易专用 WebSocket 客户端,对齐 Gate 的 GateKlineWebSocketClient 模式。
+ *
+ * <h3>职责</h3>
+ * 负责 TCP 连接的建立、维持和恢复。频道逻辑(订阅/解析)全部委托给
+ * {@link OkxGridChannelHandler} 实现类。
+ *
+ * <h3>生命周期</h3>
+ * <pre>
+ * init() → connect() → login() → subscribe handlers → startHeartbeat()
+ * destroy() → unsubscribe 所有 handler → closeBlocking() → shutdown 线程池
+ * onClose() → reconnectWithBackoff() (最多 3 次,指数退避)
+ * </pre>
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class OkxGridWsClient {
+
+ private static final int HEARTBEAT_TIMEOUT = 10;
+
+ /** 模拟盘 WS 地址 */
+ private static final String WS_URL_SIM = "wss://wspap.okx.com:8443/ws/v5/private";
+ /** 实盘 WS 地址 */
+ private static final String WS_URL_PROD = "wss://ws.okx.com:8443/ws/v5/private";
+
+ private final ExchangeInfoEnum account;
+ private WebSocketClient webSocketClient;
+ private ScheduledExecutorService heartbeatExecutor;
+ private volatile ScheduledFuture<?> pongTimeoutFuture;
+ private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
+
+ private final AtomicBoolean isConnected = new AtomicBoolean(false);
+ private final AtomicBoolean isConnecting = new AtomicBoolean(false);
+ private final AtomicBoolean isInitialized = new AtomicBoolean(false);
+
+ /** 频道处理器列表 */
+ private final List<OkxGridChannelHandler> channelHandlers = new ArrayList<>();
+
+ /** 共享线程池 */
+ private final ExecutorService sharedExecutor = Executors.newCachedThreadPool(r -> {
+ Thread t = new Thread(r, "okx-grid-ws-worker");
+ t.setDaemon(true);
+ return t;
+ });
+
+ public OkxGridWsClient(ExchangeInfoEnum account) {
+ this.account = account;
+ }
+
+ public void addChannelHandler(OkxGridChannelHandler handler) {
+ channelHandlers.add(handler);
+ }
+
+ public void init() {
+ if (!isInitialized.compareAndSet(false, true)) {
+ log.warn("[OKX-Grid-WS] 已初始化过,跳过重复初始化");
+ return;
+ }
+ connect();
+ startHeartbeat();
+ }
+
+ public void destroy() {
+ log.info("[OKX-Grid-WS] 开始销毁...");
+ if (webSocketClient != null && webSocketClient.isOpen()) {
+ for (OkxGridChannelHandler handler : channelHandlers) {
+ handler.unsubscribe(webSocketClient);
+ }
+ try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
+ }
+ if (webSocketClient != null && webSocketClient.isOpen()) {
+ try {
+ webSocketClient.closeBlocking();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ shutdownExecutorGracefully(heartbeatExecutor);
+ if (pongTimeoutFuture != null) pongTimeoutFuture.cancel(true);
+ shutdownExecutorGracefully(sharedExecutor);
+ log.info("[OKX-Grid-WS] 销毁完成");
+ }
+
+ private void connect() {
+ if (isConnecting.get() || !isConnecting.compareAndSet(false, true)) {
+ log.info("[OKX-Grid-WS] 连接进行中,跳过重复请求");
+ return;
+ }
+ try {
+ SSLConfig.configureSSL();
+ System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
+ String wsUrl = account.isAccountType() ? WS_URL_PROD : WS_URL_SIM;
+ URI uri = new URI(wsUrl);
+
+ if (webSocketClient != null) {
+ try { webSocketClient.closeBlocking(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
+ }
+
+ webSocketClient = new WebSocketClient(uri) {
+ @Override
+ public void onOpen(ServerHandshake handshake) {
+ log.info("[OKX-Grid-WS] 连接成功");
+ isConnected.set(true);
+ isConnecting.set(false);
+ if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
+ resetHeartbeatTimer();
+ wsLogin();
+ }
+ }
+
+ @Override
+ public void onMessage(String message) {
+ lastMessageTime.set(System.currentTimeMillis());
+ handleMessage(message);
+ resetHeartbeatTimer();
+ }
+
+ @Override
+ public void onClose(int code, String reason, boolean remote) {
+ log.warn("[OKX-Grid-WS] 连接关闭, code:{}, reason:{}", code, reason);
+ isConnected.set(false);
+ isConnecting.set(false);
+ cancelPongTimeout();
+ if (sharedExecutor != null && !sharedExecutor.isShutdown() && !sharedExecutor.isTerminated()) {
+ sharedExecutor.execute(() -> {
+ try { reconnectWithBackoff(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { log.error("[OKX-Grid-WS] 重连失败", e); }
+ });
+ }
+ }
+
+ @Override
+ public void onError(Exception ex) {
+ log.error("[OKX-Grid-WS] 发生错误", ex);
+ isConnected.set(false);
+ }
+ };
+ webSocketClient.connect();
+ } catch (URISyntaxException e) {
+ log.error("[OKX-Grid-WS] URI格式错误", e);
+ isConnecting.set(false);
+ }
+ }
+
+ /**
+ * WebSocket 登录认证
+ */
+ private void wsLogin() {
+ try {
+ String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+ String sign = SignUtils.signWebsocket(timestamp, account.getSecretKey());
+
+ JSONObject msg = new JSONObject();
+ msg.put("op", "login");
+ com.alibaba.fastjson.JSONArray args = new com.alibaba.fastjson.JSONArray();
+ JSONObject loginArgs = new JSONObject();
+ loginArgs.put("apiKey", account.getApiKey());
+ loginArgs.put("passphrase", account.getPassphrase());
+ loginArgs.put("timestamp", timestamp);
+ loginArgs.put("sign", sign);
+ args.add(loginArgs);
+ msg.put("args", args);
+ webSocketClient.send(msg.toJSONString());
+ log.info("[OKX-Grid-WS] 发送登录请求");
+ } catch (Exception e) {
+ log.error("[OKX-Grid-WS] 登录请求构建失败", e);
+ }
+ }
+
+ private void handleMessage(String message) {
+ try {
+ JSONObject response = JSON.parseObject(message);
+ String event = response.getString("event");
+ String op = response.getString("op");
+
+ // 登录成功 → 订阅所有频道
+ if ("login".equals(event) || ("login".equals(op))) {
+ log.info("[OKX-Grid-WS] 登录成功, 开始订阅频道");
+ for (OkxGridChannelHandler handler : channelHandlers) {
+ handler.subscribe(webSocketClient);
+ }
+ return;
+ }
+
+ // 订阅确认
+ if ("subscribe".equals(event) || "unsubscribe".equals(event)) {
+ log.info("[OKX-Grid-WS] {}事件: {}", event, response.getString("arg"));
+ return;
+ }
+
+ // 错误
+ if ("error".equals(event)) {
+ log.error("[OKX-Grid-WS] 错误: {}", message);
+ return;
+ }
+
+ // 数据推送 → 路由到 handler
+ for (OkxGridChannelHandler handler : channelHandlers) {
+ if (handler.handleMessage(response)) return;
+ }
+ } catch (Exception e) {
+ log.error("[OKX-Grid-WS] 处理消息失败: {}", message, e);
+ }
+ }
+
+ // ---- heartbeat ----
+
+ private void startHeartbeat() {
+ if (heartbeatExecutor != null && !heartbeatExecutor.isTerminated()) heartbeatExecutor.shutdownNow();
+ heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
+ Thread t = new Thread(r, "okx-grid-ws-heartbeat");
+ t.setDaemon(true);
+ return t;
+ });
+ heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout, 25, 25, TimeUnit.SECONDS);
+ }
+
+ private synchronized void resetHeartbeatTimer() {
+ cancelPongTimeout();
+ if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) {
+ pongTimeoutFuture = heartbeatExecutor.schedule(this::sendPing, HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
+ }
+ }
+
+ private void checkHeartbeatTimeout() {
+ if (!isConnected.get()) return;
+ if (System.currentTimeMillis() - lastMessageTime.get() >= HEARTBEAT_TIMEOUT * 1000L) sendPing();
+ }
+
+ private void sendPing() {
+ try {
+ if (webSocketClient != null && webSocketClient.isOpen()) {
+ webSocketClient.send("ping");
+ log.debug("[OKX-Grid-WS] 发送 ping");
+ }
+ } catch (Exception e) { log.warn("[OKX-Grid-WS] 发送 ping 失败", e); }
+ }
+
+ private synchronized void cancelPongTimeout() {
+ if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) pongTimeoutFuture.cancel(true);
+ }
+
+ private void reconnectWithBackoff() throws InterruptedException {
+ int attempt = 0, maxAttempts = 3;
+ long delayMs = 5000;
+ while (attempt < maxAttempts) {
+ try { Thread.sleep(delayMs); connect(); return; }
+ catch (Exception e) { log.warn("[OKX-Grid-WS] 第{}次重连失败", attempt + 1, e); delayMs *= 2; attempt++; }
+ }
+ log.error("[OKX-Grid-WS] 超过最大重试次数({}),放弃重连", maxAttempts);
+ }
+
+ private void shutdownExecutorGracefully(ExecutorService executor) {
+ if (executor == null || executor.isTerminated()) return;
+ try {
+ executor.shutdown();
+ if (!executor.awaitTermination(5, TimeUnit.SECONDS)) executor.shutdownNow();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ executor.shutdownNow();
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java
deleted file mode 100644
index cf5c9fd..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java
+++ /dev/null
@@ -1,577 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.json.JSONException;
-import cn.hutool.json.JSONUtil;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.blackchain.service.DateUtil;
-import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService;
-import com.xcong.excoin.modules.okxNewPrice.indicator.TradingStrategy;
-import com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy.MacdEmaStrategy;
-import com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy.MacdMaStrategy;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.*;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.Kline;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListService;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.ExchangeInfoEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.ExchangeLoginService;
-import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.handshake.ServerHandshake;
-
-import java.math.BigDecimal;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
-
-/**
- * OKX 新价格 WebSocket 客户端类,用于连接 OKX 的 WebSocket 接口,
- * 实时获取并处理标记价格(mark price)数据,并将价格信息存储到 Redis 中。
- * 同时支持心跳检测、自动重连以及异常恢复机制。
- * @author Administrator
- */
-@Slf4j
-public class OkxKlineWebSocketClient {
- private final RedisUtils redisUtils;
- private final CaoZuoService caoZuoService;
- private final OkxWebSocketClientManager clientManager;
- private final WangGeListService wangGeListService;
-
- private WebSocketClient webSocketClient;
- private ScheduledExecutorService heartbeatExecutor;
- private volatile ScheduledFuture<?> pongTimeoutFuture;
- private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
-
- // 连接状态标志
- private final AtomicBoolean isConnected = new AtomicBoolean(false);
- private final AtomicBoolean isConnecting = new AtomicBoolean(false);
- private final AtomicBoolean isInitialized = new AtomicBoolean(false);
-
-// private static final String CHANNEL = "mark-price";
- private static final String CHANNEL = "candle1m";
-// private static final String CHANNEL = "candle15m";
-
- // 心跳超时时间(秒),小于30秒
- private static final int HEARTBEAT_TIMEOUT = 10;
-
- // 共享线程池用于重连等异步任务
- private final ExecutorService sharedExecutor = Executors.newCachedThreadPool(r -> {
- Thread t = new Thread(r, "okx-ws-kline-worker");
- t.setDaemon(true);
- return t;
- });
-
- public OkxKlineWebSocketClient(RedisUtils redisUtils,
- CaoZuoService caoZuoService, OkxWebSocketClientManager clientManager,
- WangGeListService wangGeListService) {
- this.redisUtils = redisUtils;
- this.caoZuoService = caoZuoService;
- this.clientManager = clientManager;
- this.wangGeListService = wangGeListService;
- }
-
- /**
- * 初始化方法,创建并初始化WebSocket客户端实例
- */
- public void init() {
- if (!isInitialized.compareAndSet(false, true)) {
- log.warn("OkxKlineWebSocketClient 已经初始化过,跳过重复初始化");
- return;
- }
- connect();
- startHeartbeat();
- }
-
- /**
- * 销毁方法,关闭WebSocket连接和相关资源
- */
- public void destroy() {
- log.info("开始销毁OkxKlineWebSocketClient");
-
- // 设置关闭标志,避免重连
- if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
- sharedExecutor.shutdown();
- }
-
- if (webSocketClient != null && webSocketClient.isOpen()) {
- try {
- webSocketClient.closeBlocking();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("关闭WebSocket连接时被中断");
- }
- }
-
- shutdownExecutorGracefully(heartbeatExecutor);
- if (pongTimeoutFuture != null) {
- pongTimeoutFuture.cancel(true);
- }
- shutdownExecutorGracefully(sharedExecutor);
-
- log.info("OkxKlineWebSocketClient销毁完成");
- }
-
- private static final String WS_URL_MONIPAN = "wss://wspap.okx.com:8443/ws/v5/business";
- private static final String WS_URL_SHIPAN = "wss://ws.okx.com:8443/ws/v5/business";
- private static final boolean isAccountType = false;
-
- /**
- * 建立与 OKX WebSocket 服务器的连接。
- * 设置回调函数以监听连接打开、接收消息、关闭和错误事件。
- */
- private void connect() {
- // 避免重复连接
- if (isConnecting.get()) {
- log.info("连接已在进行中,跳过重复连接请求");
- return;
- }
-
- if (!isConnecting.compareAndSet(false, true)) {
- log.info("连接已在进行中,跳过重复连接请求");
- return;
- }
-
- try {
- SSLConfig.configureSSL();
- System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
- String WS_URL = WS_URL_MONIPAN;
- if (isAccountType){
- WS_URL = WS_URL_SHIPAN;
- }
- URI uri = new URI(WS_URL);
-
- // 关闭之前的连接(如果存在)
- if (webSocketClient != null) {
- try {
- webSocketClient.closeBlocking();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("关闭之前连接时被中断");
- }
- }
-
- webSocketClient = new WebSocketClient(uri) {
- @Override
- public void onOpen(ServerHandshake handshake) {
- log.info("OKX kline WebSocket连接成功");
- isConnected.set(true);
- isConnecting.set(false);
-
- // 检查应用是否正在关闭
- if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
- resetHeartbeatTimer();
- subscribeChannels();
- } else {
- log.warn("应用正在关闭,忽略WebSocket连接成功回调");
- }
- }
-
- @Override
- public void onMessage(String message) {
- lastMessageTime.set(System.currentTimeMillis());
- handleWebSocketMessage(message);
- resetHeartbeatTimer();
- }
-
- @Override
- public void onClose(int code, String reason, boolean remote) {
- log.warn("OKX kline WebSocket连接关闭: code={}, reason={}", code, reason);
- isConnected.set(false);
- isConnecting.set(false);
- cancelPongTimeout();
-
- if (sharedExecutor != null && !sharedExecutor.isShutdown() && !sharedExecutor.isTerminated()) {
- sharedExecutor.execute(() -> {
- try {
- reconnectWithBackoff();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.error("重连线程被中断", e);
- } catch (Exception e) {
- log.error("重连失败", e);
- }
- });
- } else {
- log.warn("共享线程池已关闭,无法执行重连任务");
- }
- }
-
- @Override
- public void onError(Exception ex) {
- log.error("OKX New Price WebSocket发生错误", ex);
- isConnected.set(false);
- }
- };
-
- webSocketClient.connect();
- } catch (URISyntaxException e) {
- log.error("WebSocket URI格式错误", e);
- isConnecting.set(false);
- }
- }
-
- /**
- * 订阅指定交易对的价格通道。
- * 构造订阅请求并发送给服务端。
- */
- private void subscribeChannels() {
- JSONObject subscribeMsg = new JSONObject();
- subscribeMsg.put("op", "subscribe");
-
- JSONArray argsArray = new JSONArray();
- JSONObject arg = new JSONObject();
- arg.put("channel", CHANNEL);
- arg.put("instId", CoinEnums.HE_YUE.getCode());
- argsArray.add(arg);
-
- subscribeMsg.put("args", argsArray);
- webSocketClient.send(subscribeMsg.toJSONString());
- log.info("已发送 K线频道订阅请求,订阅通道数: {}", argsArray.size());
- }
-
- /**
- * 处理从 WebSocket 收到的消息。
- * 包括订阅确认、错误响应、心跳响应以及实际的数据推送。
- *
- * @param message 来自 WebSocket 的原始字符串消息
- */
- private void handleWebSocketMessage(String message) {
- try {
- if ("pong".equals(message)) {
- log.debug("{}: 收到心跳响应");
- cancelPongTimeout();
- return;
- }
- JSONObject response = JSON.parseObject(message);
- String event = response.getString("event");
-
- if ("subscribe".equals(event)) {
- log.info(" K线频道订阅成功: {}", response.getJSONObject("arg"));
- } else if ("error".equals(event)) {
- log.error(" K线频道订阅错误: code={}, msg={}",
- response.getString("code"), response.getString("msg"));
- } else if ("pong".equals(event)) {
- log.debug("收到pong响应");
- cancelPongTimeout();
- } else {
-// processPushData(response);
- processPushDataV2(response);
- }
- } catch (Exception e) {
- log.error("处理WebSocket消息失败: {}", message, e);
- }
- }
-
- /**
- * 解析并处理价格推送数据。
- * 将最新的标记价格存入 Redis 并触发后续业务逻辑比较处理。
- * 当价格变化时,调用CaoZuoService的caoZuo方法,触发所有账号的量化操作
- *
- * @param response 包含价格数据的 JSON 对象
- */
- private void processPushDataV2(JSONObject response) {
- try {
- /**
- * {
- * "arg": {
- * "channel": "candle1D",
- * "instId": "BTC-USDT"
- * },
- * "data": [
- * [
- * "1629993600000",
- * "42500",
- * "48199.9",
- * "41006.1",
- * "41006.1",
- * "3587.41204591",
- * "166741046.22583129",
- * "166741046.22583129",
- * "0"
- * ]
- * ]
- * }
- */
- JSONObject arg = response.getJSONObject("arg");
- if (arg == null) {
- log.warn("{}: 无效的推送数据,缺少 'arg' 字段", response);
- return;
- }
-
- String channel = arg.getString("channel");
- if (channel == null) {
- log.warn("{}: 无效的推送数据,缺少 'channel' 字段", response);
- return;
- }
-
- String instId = arg.getString("instId");
- if (instId == null) {
- log.warn("{}: 无效的推送数据,缺少 'instId' 字段", response);
- return;
- }
-
- if (CHANNEL.equals(channel) && CoinEnums.HE_YUE.getCode().equals(instId)) {
- JSONArray dataArray = response.getJSONArray("data");
- if (dataArray == null || dataArray.isEmpty()) {
- log.warn("K线频道数据为空");
- return;
- }
- JSONArray data = dataArray.getJSONArray(0);
- BigDecimal openPx = new BigDecimal(data.getString(1));
- BigDecimal highPx = new BigDecimal(data.getString(2));
- BigDecimal lowPx = new BigDecimal(data.getString(3));
- BigDecimal closePx = new BigDecimal(data.getString(4));
- BigDecimal vol = new BigDecimal(data.getString(5));
- //ts String 开始时间,Unix时间戳的毫秒数格式,如 1597026383085 转日期:2020-08-07 15:13:03.085
- String time = DateUtil.TimeStampToDateTime(Long.parseLong(data.getString(0)));
- /**
- * K线状态
- * 0:K线未完结
- * 1:K线已完结
- */
- String confirm = data.getString(8);
- if ("1".equals(confirm)){
- //调用策略
- // 创建策略实例
- MacdEmaStrategy strategy = new MacdEmaStrategy();
-
- // 生成200个1m价格数据点
- List<Kline> kline1MinuteData = getKlineDataByInstIdAndBar(instId, "1m");
- List<BigDecimal> historicalPrices1M = kline1MinuteData.stream()
- .map(Kline::getC)
- .collect(Collectors.toList());
-
- // 使用策略分析最新价格数据
- MacdEmaStrategy.TradingOrder tradingOrderOpenOpen = strategy.generateTradingOrder(historicalPrices1M, MacdMaStrategy.OperationType.open.name());
- if (tradingOrderOpenOpen == null){
- return;
- }
-
- Collection<OkxQuantWebSocketClient> allClients = clientManager.getAllClients();
- //如果为空,则直接返回
- if (allClients.isEmpty()) {
- return;
- }
- // 获取所有OkxQuantWebSocketClient实例
- for (OkxQuantWebSocketClient client : clientManager.getAllClients()) {
- String accountName = client.getAccountName();
- if (accountName != null) {
- if (ObjectUtil.isNotEmpty(tradingOrderOpenOpen)){
- log.info("{}开仓{}:{}",instId,tradingOrderOpenOpen.getPosSide(),tradingOrderOpenOpen.getSide());
- doOpen(client.getWebSocketClient(),accountName, tradingOrderOpenOpen, closePx);
- }
- }
- }
- }
- }
- } catch (Exception e) {
- log.error("处理 K线频道推送数据失败", e);
- }
- }
-
- private void doOpen(WebSocketClient webSocketClient, String accountName, MacdEmaStrategy.TradingOrder tradingOrderOpenOpen, BigDecimal closePx) {
- // 根据信号执行交易操作
- TradeRequestParam tradeRequestParam = new TradeRequestParam();
-
- String posSide = tradingOrderOpenOpen.getPosSide();
- tradeRequestParam.setPosSide(posSide);
- String currentPrice = String.valueOf(closePx);
- tradeRequestParam = caoZuoService.caoZuoStrategy(accountName, currentPrice, posSide);
-
- String side = tradingOrderOpenOpen.getSide();
- tradeRequestParam.setSide(side);
-
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
-
- String sz = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.BUY_CNT_INIT.name());
- tradeRequestParam.setSz(sz);
- TradeOrderWs.orderEvent(webSocketClient, tradeRequestParam);
- }
-
- private List<Kline> getKlineDataByInstIdAndBar(String instId, String bar) {
- List<Kline> klineList = new ArrayList<>();
- try {
- LinkedHashMap<String, Object> requestParam = new LinkedHashMap<>();
- requestParam.put("instId", instId);
- requestParam.put("bar", bar);
- requestParam.put("limit", "200");
- String result = ExchangeLoginService.getInstance(ExchangeInfoEnum.OKX_UAT.name()).lineHistory(requestParam);
- JSONObject json = JSON.parseObject(result);
- String data = json.getString("data");
-
- if (data != null) {
- List<String[]> klinesList = JSON.parseArray(data, String[].class);
- if (!CollUtil.isEmpty(klinesList)) {
- for (String[] s : klinesList) {
- // 确保数组有足够的元素
- if (s != null && s.length >= 9) {
- String s1 = s[8];
- try {
- if ("1".equals(s1)){
- Kline kline = new Kline();
- kline.setTs(s[0]);
- kline.setO(new BigDecimal(s[1]));
- kline.setH(new BigDecimal(s[2]));
- kline.setL(new BigDecimal(s[3]));
- kline.setC(new BigDecimal(s[4]));
- kline.setVol(new BigDecimal(s[5]));
- kline.setConfirm(s[8]);
- klineList.add(kline);
- }
- } catch (NumberFormatException e) {
- log.error("K线数据转换为BigDecimal失败: {}", Arrays.toString(s), e);
- }
- } else {
- log.warn("K线数据数组长度不足: {}", Arrays.toString(s));
- }
- }
- }
- } else {
- log.warn("K线数据为空");
- }
- } catch (JSONException e) {
- log.error("K线数据解析失败", e);
- } catch (Exception e) {
- log.error("获取K线数据异常", e);
- }
- return klineList;
- }
-
- /**
- * 构建 Redis Key
- */
- private String buildRedisKey(String instId) {
- return "PRICE_" + instId.replace("-", "");
- }
-
- /**
- * 启动心跳检测任务。
- * 使用 ScheduledExecutorService 定期检查是否需要发送 ping 请求来维持连接。
- */
- private void startHeartbeat() {
- if (heartbeatExecutor != null && !heartbeatExecutor.isTerminated()) {
- heartbeatExecutor.shutdownNow();
- }
-
- heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
- Thread t = new Thread(r, "okx-kline-heartbeat");
- t.setDaemon(true);
- return t;
- });
-
- heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout, 25, 25, TimeUnit.SECONDS);
- }
-
- /**
- * 重置心跳计时器。
- * 当收到新消息或发送 ping 后取消当前超时任务并重新安排下一次超时检查。
- */
- private synchronized void resetHeartbeatTimer() {
- cancelPongTimeout();
-
- if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) {
- pongTimeoutFuture = heartbeatExecutor.schedule(this::checkHeartbeatTimeout,
- HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
- }
- }
-
- /**
- * 检查心跳超时情况。
- * 若长时间未收到任何消息则主动发送 ping 请求保持连接活跃。
- */
- private void checkHeartbeatTimeout() {
- // 只有在连接状态下才检查心跳
- if (!isConnected.get()) {
- return;
- }
-
- long currentTime = System.currentTimeMillis();
- long lastTime = lastMessageTime.get();
-
- if (currentTime - lastTime >= HEARTBEAT_TIMEOUT * 1000L) {
- sendPing();
- }
- }
-
- /**
- * 发送 ping 请求至 WebSocket 服务端。
- * 用于维持长连接有效性。
- */
- private void sendPing() {
- try {
- if (webSocketClient != null && webSocketClient.isOpen()) {
- webSocketClient.send("ping");
- log.debug("发送ping请求");
- }
- } catch (Exception e) {
- log.warn("发送ping失败", e);
- }
- }
-
- /**
- * 取消当前的心跳超时任务。
- * 在收到 pong 或其他有效消息时调用此方法避免不必要的断开重连。
- */
- private synchronized void cancelPongTimeout() {
- if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) {
- pongTimeoutFuture.cancel(true);
- }
- }
-
- /**
- * 执行 WebSocket 重连操作。
- * 在连接意外中断后尝试重新建立连接。
- */
- private void reconnectWithBackoff() throws InterruptedException {
- int attempt = 0;
- int maxAttempts = 3;
- long delayMs = 5000;
-
- while (attempt < maxAttempts) {
- try {
- Thread.sleep(delayMs);
- connect();
- return;
- } catch (Exception e) {
- log.warn("第{}次重连失败", attempt + 1, e);
- delayMs *= 2;
- attempt++;
- }
- }
-
- log.error("超过最大重试次数({})仍未连接成功", maxAttempts);
- }
-
- /**
- * 优雅关闭线程池
- */
- private void shutdownExecutorGracefully(ExecutorService executor) {
- if (executor == null || executor.isTerminated()) {
- return;
- }
- try {
- executor.shutdown();
- if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
- executor.shutdownNow();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- executor.shutdownNow();
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxNewPriceWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxNewPriceWebSocketClient.java
deleted file mode 100644
index 782467e..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxNewPriceWebSocketClient.java
+++ /dev/null
@@ -1,468 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.TradeOrderWs;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListService;
-import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig;
-import com.xcong.excoin.utils.RedisUtils;
-import java.math.BigDecimal;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.handshake.ServerHandshake;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collection;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * OKX 新价格 WebSocket 客户端类,用于连接 OKX 的 WebSocket 接口,
- * 实时获取并处理标记价格(mark price)数据,并将价格信息存储到 Redis 中。
- * 同时支持心跳检测、自动重连以及异常恢复机制。
- * @author Administrator
- */
-@Slf4j
-public class OkxNewPriceWebSocketClient {
- private final RedisUtils redisUtils;
- private final CaoZuoService caoZuoService;
- private final OkxWebSocketClientManager clientManager;
- private final WangGeListService wangGeListService;
-
- private WebSocketClient webSocketClient;
- private ScheduledExecutorService heartbeatExecutor;
- private volatile ScheduledFuture<?> pongTimeoutFuture;
- private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
-
- // 连接状态标志
- private final AtomicBoolean isConnected = new AtomicBoolean(false);
- private final AtomicBoolean isConnecting = new AtomicBoolean(false);
- private final AtomicBoolean isInitialized = new AtomicBoolean(false);
-
- private static final String CHANNEL = "mark-price";
-
- // 心跳超时时间(秒),小于30秒
- private static final int HEARTBEAT_TIMEOUT = 10;
-
- // 共享线程池用于重连等异步任务
- private final ExecutorService sharedExecutor = Executors.newCachedThreadPool(r -> {
- Thread t = new Thread(r, "okx-ws-shared-worker");
- t.setDaemon(true);
- return t;
- });
-
- public OkxNewPriceWebSocketClient(RedisUtils redisUtils,
- CaoZuoService caoZuoService, OkxWebSocketClientManager clientManager,
- WangGeListService wangGeListService) {
- this.redisUtils = redisUtils;
- this.caoZuoService = caoZuoService;
- this.clientManager = clientManager;
- this.wangGeListService = wangGeListService;
- }
-
- /**
- * 初始化方法,创建并初始化WebSocket客户端实例
- */
- public void init() {
- if (!isInitialized.compareAndSet(false, true)) {
- log.warn("OkxNewPriceWebSocketClient 已经初始化过,跳过重复初始化");
- return;
- }
- connect();
- startHeartbeat();
- }
-
- /**
- * 销毁方法,关闭WebSocket连接和相关资源
- */
- public void destroy() {
- log.info("开始销毁OkxNewPriceWebSocketClient");
-
- // 设置关闭标志,避免重连
- if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
- sharedExecutor.shutdown();
- }
-
- if (webSocketClient != null && webSocketClient.isOpen()) {
- try {
- webSocketClient.closeBlocking();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("关闭WebSocket连接时被中断");
- }
- }
-
- shutdownExecutorGracefully(heartbeatExecutor);
- if (pongTimeoutFuture != null) {
- pongTimeoutFuture.cancel(true);
- }
- shutdownExecutorGracefully(sharedExecutor);
-
- log.info("OkxNewPriceWebSocketClient销毁完成");
- }
-
- private static final String WS_URL_MONIPAN = "wss://wspap.okx.com:8443/ws/v5/public";
- private static final String WS_URL_SHIPAN = "wss://ws.okx.com:8443/ws/v5/public";
- private static final boolean isAccountType = true;
-
- /**
- * 建立与 OKX WebSocket 服务器的连接。
- * 设置回调函数以监听连接打开、接收消息、关闭和错误事件。
- */
- private void connect() {
- // 避免重复连接
- if (isConnecting.get()) {
- log.info("连接已在进行中,跳过重复连接请求");
- return;
- }
-
- if (!isConnecting.compareAndSet(false, true)) {
- log.info("连接已在进行中,跳过重复连接请求");
- return;
- }
-
- try {
- SSLConfig.configureSSL();
- System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
- String WS_URL = WS_URL_MONIPAN;
- if (isAccountType){
- WS_URL = WS_URL_SHIPAN;
- }
- URI uri = new URI(WS_URL);
-
- // 关闭之前的连接(如果存在)
- if (webSocketClient != null) {
- try {
- webSocketClient.closeBlocking();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("关闭之前连接时被中断");
- }
- }
-
- webSocketClient = new WebSocketClient(uri) {
- @Override
- public void onOpen(ServerHandshake handshake) {
- log.info("OKX New Price WebSocket连接成功");
- isConnected.set(true);
- isConnecting.set(false);
-
- // 检查应用是否正在关闭
- if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
- resetHeartbeatTimer();
- subscribeChannels();
- } else {
- log.warn("应用正在关闭,忽略WebSocket连接成功回调");
- }
- }
-
- @Override
- public void onMessage(String message) {
- lastMessageTime.set(System.currentTimeMillis());
- handleWebSocketMessage(message);
- resetHeartbeatTimer();
- }
-
- @Override
- public void onClose(int code, String reason, boolean remote) {
- log.warn("OKX New Price WebSocket连接关闭: code={}, reason={}", code, reason);
- isConnected.set(false);
- isConnecting.set(false);
- cancelPongTimeout();
-
- if (sharedExecutor != null && !sharedExecutor.isShutdown() && !sharedExecutor.isTerminated()) {
- sharedExecutor.execute(() -> {
- try {
- reconnectWithBackoff();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.error("重连线程被中断", e);
- } catch (Exception e) {
- log.error("重连失败", e);
- }
- });
- } else {
- log.warn("共享线程池已关闭,无法执行重连任务");
- }
- }
-
- @Override
- public void onError(Exception ex) {
- log.error("OKX New Price WebSocket发生错误", ex);
- isConnected.set(false);
- }
- };
-
- webSocketClient.connect();
- } catch (URISyntaxException e) {
- log.error("WebSocket URI格式错误", e);
- isConnecting.set(false);
- }
- }
-
- /**
- * 订阅指定交易对的价格通道。
- * 构造订阅请求并发送给服务端。
- */
- private void subscribeChannels() {
- JSONObject subscribeMsg = new JSONObject();
- subscribeMsg.put("op", "subscribe");
-
- JSONArray argsArray = new JSONArray();
- JSONObject arg = new JSONObject();
- arg.put("channel", CHANNEL);
- arg.put("instId", CoinEnums.HE_YUE.getCode());
- argsArray.add(arg);
-
- subscribeMsg.put("args", argsArray);
- webSocketClient.send(subscribeMsg.toJSONString());
- log.info("已发送价格订阅请求,订阅通道数: {}", argsArray.size());
- }
-
- /**
- * 处理从 WebSocket 收到的消息。
- * 包括订阅确认、错误响应、心跳响应以及实际的数据推送。
- *
- * @param message 来自 WebSocket 的原始字符串消息
- */
- private void handleWebSocketMessage(String message) {
- try {
- JSONObject response = JSON.parseObject(message);
- String event = response.getString("event");
-
- if ("subscribe".equals(event)) {
- log.info("价格订阅成功: {}", response.getJSONObject("arg"));
- } else if ("error".equals(event)) {
- log.error("价格订阅错误: code={}, msg={}",
- response.getString("code"), response.getString("msg"));
- } else if ("pong".equals(event)) {
- log.debug("收到pong响应");
- cancelPongTimeout();
- } else {
- processPushData(response);
- }
- } catch (Exception e) {
- log.error("处理WebSocket消息失败: {}", message, e);
- }
- }
-
- /**
- * 解析并处理价格推送数据。
- * 将最新的标记价格存入 Redis 并触发后续业务逻辑比较处理。
- * 当价格变化时,调用CaoZuoService的caoZuo方法,触发所有账号的量化操作
- *
- * @param response 包含价格数据的 JSON 对象
- */
- private void processPushData(JSONObject response) {
- try {
- JSONArray dataArray = response.getJSONArray("data");
- if (dataArray != null && !dataArray.isEmpty()) {
- for (int i = 0; i < dataArray.size(); i++) {
- try {
- JSONObject priceData = dataArray.getJSONObject(i);
- String instId = priceData.getString("instId");
- String markPx = priceData.getString("markPx");
- // 保存价格到Redis
- redisUtils.set(CoinEnums.HE_YUE.getCode(), markPx);
-
- log.debug("更新最新价格: {} = {}, 币种: {}", CoinEnums.HE_YUE.getCode(), markPx, instId);
-
- // 价格变化时,触发所有账号的量化操作
- triggerQuantOperations(markPx);
- } catch (Exception innerEx) {
- log.warn("处理单条价格数据失败", innerEx);
- }
- }
- }
- } catch (Exception e) {
- log.error("处理价格推送数据失败", e);
- }
- }
-
- /**
- * 触发所有账号的量化操作
- * @param markPx 当前标记价格
- */
- private void triggerQuantOperations(String markPx) {
- try {
- // 1. 判断当前价格属于哪个网格
- WangGeListEnum gridByPriceNew = WangGeListEnum.getGridByPrice(new BigDecimal(markPx));
- if (gridByPriceNew == null) {
- log.error("当前价格{}不在任何网格范围内,无法触发量化操作", markPx);
- return;
- }
- /**
- * 获取当前网格信息
- * 根据当前网格的持仓方向获取反方向是否存在持仓
- * 如果持有,直接止损
- */
- Collection<OkxQuantWebSocketClient> allClients = clientManager.getAllClients();
- //如果为空,则直接返回
- if (allClients.isEmpty()) {
- return;
- }
- // 获取所有OkxQuantWebSocketClient实例
- for (OkxQuantWebSocketClient client : clientManager.getAllClients()) {
- String accountName = client.getAccountName();
- if (accountName != null) {
- /**
- * 处理历史网格的订单
- * 根据历史网格的开单方向,是否需要止损处理
- * 如果方向一致就不需要处理
- * 如果不一致则需要处理
- */
- String fangXiang = gridByPriceNew.getFang_xiang();
- String fangXiangOld = CoinEnums.POSSIDE_LONG.getCode().equals(fangXiang) ? CoinEnums.POSSIDE_SHORT.getCode() : CoinEnums.POSSIDE_LONG.getCode();
- log.info("历史网格方向为:{}", fangXiangOld);
- if (!fangXiang.equals(fangXiangOld)){
- TradeRequestParam tradeRequestParamOld = caoZuoService.caoZuoZhiSunEvent(accountName, markPx, fangXiangOld);
- TradeOrderWs.orderEvent(client.getWebSocketClient(), tradeRequestParamOld);
- }
-
- /**
- * 处理当前网格的订单,触发量化操作
- */
- log.info("当前价格{}属于网格: {}-{}({}-{})", markPx, gridByPriceNew.getName(),gridByPriceNew.getFang_xiang(), gridByPriceNew.getJiage_xiaxian(), gridByPriceNew.getJiage_shangxian());
- wangGeListService.initWangGe(markPx);
- TradeRequestParam tradeRequestParam = caoZuoService.caoZuoHandler(accountName, markPx, gridByPriceNew.getFang_xiang());
- TradeOrderWs.orderEvent(client.getWebSocketClient(), tradeRequestParam);
- log.info("价格变化触发量化操作: 账号={}, 价格={}", accountName, markPx);
- }
- }
- } catch (Exception e) {
- log.error("触发量化操作失败", e);
- }
- }
-
- /**
- * 构建 Redis Key
- */
- private String buildRedisKey(String instId) {
- return "PRICE_" + instId.replace("-", "");
- }
-
- /**
- * 启动心跳检测任务。
- * 使用 ScheduledExecutorService 定期检查是否需要发送 ping 请求来维持连接。
- */
- private void startHeartbeat() {
- if (heartbeatExecutor != null && !heartbeatExecutor.isTerminated()) {
- heartbeatExecutor.shutdownNow();
- }
-
- heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
- Thread t = new Thread(r, "okx-newprice-heartbeat");
- t.setDaemon(true);
- return t;
- });
-
- heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout, 25, 25, TimeUnit.SECONDS);
- }
-
- /**
- * 重置心跳计时器。
- * 当收到新消息或发送 ping 后取消当前超时任务并重新安排下一次超时检查。
- */
- private synchronized void resetHeartbeatTimer() {
- cancelPongTimeout();
-
- if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) {
- pongTimeoutFuture = heartbeatExecutor.schedule(this::checkHeartbeatTimeout,
- HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
- }
- }
-
- /**
- * 检查心跳超时情况。
- * 若长时间未收到任何消息则主动发送 ping 请求保持连接活跃。
- */
- private void checkHeartbeatTimeout() {
- // 只有在连接状态下才检查心跳
- if (!isConnected.get()) {
- return;
- }
-
- long currentTime = System.currentTimeMillis();
- long lastTime = lastMessageTime.get();
-
- if (currentTime - lastTime >= HEARTBEAT_TIMEOUT * 1000L) {
- sendPing();
- }
- }
-
- /**
- * 发送 ping 请求至 WebSocket 服务端。
- * 用于维持长连接有效性。
- */
- private void sendPing() {
- try {
- if (webSocketClient != null && webSocketClient.isOpen()) {
- JSONObject ping = new JSONObject();
- ping.put("op", "ping");
- webSocketClient.send(ping.toJSONString());
- log.debug("发送ping请求");
- }
- } catch (Exception e) {
- log.warn("发送ping失败", e);
- }
- }
-
- /**
- * 取消当前的心跳超时任务。
- * 在收到 pong 或其他有效消息时调用此方法避免不必要的断开重连。
- */
- private synchronized void cancelPongTimeout() {
- if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) {
- pongTimeoutFuture.cancel(true);
- }
- }
-
- /**
- * 执行 WebSocket 重连操作。
- * 在连接意外中断后尝试重新建立连接。
- */
- private void reconnectWithBackoff() throws InterruptedException {
- int attempt = 0;
- int maxAttempts = 3;
- long delayMs = 5000;
-
- while (attempt < maxAttempts) {
- try {
- Thread.sleep(delayMs);
- connect();
- return;
- } catch (Exception e) {
- log.warn("第{}次重连失败", attempt + 1, e);
- delayMs *= 2;
- attempt++;
- }
- }
-
- log.error("超过最大重试次数({})仍未连接成功", maxAttempts);
- }
-
- /**
- * 优雅关闭线程池
- */
- private void shutdownExecutorGracefully(ExecutorService executor) {
- if (executor == null || executor.isTerminated()) {
- return;
- }
- try {
- executor.shutdown();
- if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
- executor.shutdownNow();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- executor.shutdownNow();
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java
deleted file mode 100644
index fd30e06..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java
+++ /dev/null
@@ -1,517 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.*;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.ExchangeInfoEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.handshake.ServerHandshake;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.math.BigDecimal;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * OKX 新价格 WebSocket 客户端类,用于连接 OKX 的 WebSocket 接口,
- * 实时获取并处理标记价格(mark price)数据,并将价格信息存储到 Redis 中。
- * 同时支持心跳检测、自动重连以及异常恢复机制。
- * @author Administrator
- */
-@Slf4j
-public class OkxQuantWebSocketClient {
- private final RedisUtils redisUtils;
- private final ExchangeInfoEnum account;
- private final CaoZuoService caoZuoService;
-
- private WebSocketClient webSocketClient;
- private ScheduledExecutorService heartbeatExecutor;
- private volatile ScheduledFuture<?> pongTimeoutFuture;
- private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
-
- // 连接状态标志
- private final AtomicBoolean isConnected = new AtomicBoolean(false);
- private final AtomicBoolean isConnecting = new AtomicBoolean(false);
-
- /**
- * 获取WebSocketClient实例
- * @return WebSocketClient实例
- */
- public WebSocketClient getWebSocketClient() {
- return webSocketClient;
- }
-
- /**
- * 获取账号名称
- * @return 账号名称
- */
- public String getAccountName() {
- return account.name();
- }
-
- public OkxQuantWebSocketClient(ExchangeInfoEnum account,
- CaoZuoService caoZuoService,
- RedisUtils redisUtils) {
- this.account = account;
- this.caoZuoService = caoZuoService;
- this.redisUtils = redisUtils;
- }
-
- private static final String WS_URL_MONIPAN = "wss://wspap.okx.com:8443/ws/v5/private";
- private static final String WS_URL_SHIPAN = "wss://ws.okx.com:8443/ws/v5/private";
-
- /**
- * 订阅频道指令
- */
- private static final String SUBSCRIBE = "subscribe";
- private static final String UNSUBSCRIBE = "unsubscribe";
-
- // 心跳超时时间(秒),小于30秒
- private static final int HEARTBEAT_TIMEOUT = 10;
-
- // 共享线程池用于重连等异步任务
- private final ExecutorService sharedExecutor = Executors.newCachedThreadPool(r -> {
- Thread t = new Thread(r, "okx-ws-account-order-worker");
- t.setDaemon(true);
- return t;
- });
-
- // 在 OkxQuantWebSocketClient 中添加初始化标记
- private final AtomicBoolean isInitialized = new AtomicBoolean(false);
-
- /**
- * 初始化方法,在 Spring Bean 构造完成后执行。
- * 负责建立 WebSocket 连接并启动心跳检测任务。
- */
- @PostConstruct
- public void init() {
- // 防止重复初始化
- if (!isInitialized.compareAndSet(false, true)) {
- log.warn("OkxQuantWebSocketClient 已经初始化过,跳过重复初始化");
- return;
- }
-
- connect();
- startHeartbeat();
- }
-
- /**
- * 销毁方法,在 Spring Bean 销毁前执行。
- * 关闭 WebSocket 连接、停止心跳定时器及相关的线程资源。
- */
-// @PreDestroy
-// public void destroy() {
-// if (webSocketClient != null && webSocketClient.isOpen()) {
-// subscribeAccountChannel(UNSUBSCRIBE);
-// subscribePositionChannel(UNSUBSCRIBE);
-// subscribeOrderInfoChannel(UNSUBSCRIBE);
-// webSocketClient.close();
-// }
-// shutdownExecutorGracefully(heartbeatExecutor);
-// if (pongTimeoutFuture != null) {
-// pongTimeoutFuture.cancel(true);
-// }
-// shutdownExecutorGracefully(sharedExecutor);
-//
-// // 移除了 reconnectScheduler 的关闭操作
-// }
- @PreDestroy
- public void destroy() {
- log.info("开始销毁OkxQuantWebSocketClient");
-
- // 设置关闭标志,避免重连
- if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
- sharedExecutor.shutdown();
- }
-
- if (webSocketClient != null && webSocketClient.isOpen()) {
- try {
- subscribeAccountChannel(UNSUBSCRIBE);
- subscribePositionChannel(UNSUBSCRIBE);
- subscribeOrderInfoChannel(UNSUBSCRIBE);
- webSocketClient.closeBlocking();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("关闭WebSocket连接时被中断");
- }
- }
-
- shutdownExecutorGracefully(heartbeatExecutor);
- if (pongTimeoutFuture != null) {
- pongTimeoutFuture.cancel(true);
- }
- shutdownExecutorGracefully(sharedExecutor);
-
- log.info("OkxQuantWebSocketClient销毁完成");
- }
-
- private void shutdownExecutorGracefully(ExecutorService executor) {
- if (executor == null || executor.isTerminated()) {
- return;
- }
- try {
- executor.shutdown();
- if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
- executor.shutdownNow();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- executor.shutdownNow();
- }
- }
-
- /**
- * 建立与 OKX WebSocket 服务器的连接。
- * 设置回调函数以监听连接打开、接收消息、关闭和错误事件。
- */
- private void connect() {
- // 避免重复连接
- if (isConnecting.get()) {
- log.info("连接已在进行中,跳过重复连接请求");
- return;
- }
-
- if (!isConnecting.compareAndSet(false, true)) {
- log.info("连接已在进行中,跳过重复连接请求");
- return;
- }
-
- try {
- InstrumentsWs.handleEvent(account.name());
- SSLConfig.configureSSL();
- System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
- String WS_URL = WS_URL_MONIPAN;
- if (account.isAccountType()){
- WS_URL = WS_URL_SHIPAN;
- }
- URI uri = new URI(WS_URL);
-
- // 关闭之前的连接(如果存在)
- if (webSocketClient != null) {
- try {
- webSocketClient.closeBlocking();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.warn("关闭之前连接时被中断");
- }
- }
-
- webSocketClient = new WebSocketClient(uri) {
- @Override
- public void onOpen(ServerHandshake handshake) {
- log.info("OKX account-order WebSocket连接成功");
- isConnected.set(true);
- isConnecting.set(false);
-
- // 棜查应用是否正在关闭
- if (!sharedExecutor.isShutdown()) {
- resetHeartbeatTimer();
- websocketLogin(account);
- } else {
- log.warn("应用正在关闭,忽略WebSocket连接成功回调");
- }
- }
-
- @Override
- public void onMessage(String message) {
- lastMessageTime.set(System.currentTimeMillis());
- handleWebSocketMessage(message);
- resetHeartbeatTimer();
- }
-
- @Override
- public void onClose(int code, String reason, boolean remote) {
- log.warn("OKX account-order WebSocket连接关闭: code={}, reason={}", code, reason);
- isConnected.set(false);
- isConnecting.set(false);
- cancelPongTimeout();
-
- if (sharedExecutor != null && !sharedExecutor.isShutdown() && !sharedExecutor.isTerminated()) {
- sharedExecutor.execute(() -> {
- try {
- reconnectWithBackoff();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.error("重连线程被中断", e);
- } catch (Exception e) {
- log.error("重连失败", e);
- }
- });
- } else {
- log.warn("共享线程池已关闭,无法执行重连任务");
- }
- }
-
- @Override
- public void onError(Exception ex) {
- log.error("OKX account-order WebSocket发生错误", ex);
- isConnected.set(false);
- }
- };
-
- webSocketClient.connect();
- } catch (URISyntaxException e) {
- log.error("WebSocket URI格式错误", e);
- isConnecting.set(false);
- }
- }
-
- private void websocketLogin(ExchangeInfoEnum account) {
- LoginWs.websocketLogin(webSocketClient, account);
- }
-
- private void subscribeBalanceAndPositionChannel(String option) {
- BalanceAndPositionWs.subscribeBalanceAndPositionChannel(webSocketClient, option);
- }
-
- private void subscribeOrderInfoChannel(String option) {
- OrderInfoWs.subscribeOrderInfoChannel(webSocketClient, option);
- }
-
- private void subscribeAccountChannel(String option) {
- AccountWs.subscribeAccountChannel(webSocketClient, option);
- }
-
- private void subscribePositionChannel(String option) {
- PositionsWs.subscribePositionChannel(webSocketClient, option);
- }
-
- /**
- * 处理从 WebSocket 收到的消息。
- * 包括订阅确认、错误响应、心跳响应以及实际的数据推送。
- *
- * @param message 来自 WebSocket 的原始字符串消息
- */
- private void handleWebSocketMessage(String message) {
- try {
- if ("pong".equals(message)) {
- log.debug("{}: 收到心跳响应", account.name());
- cancelPongTimeout();
- return;
- }
- JSONObject response = JSON.parseObject(message);
- String event = response.getString("event");
-
- if ("login".equals(event)) {
- String code = response.getString("code");
- if ("0".equals(code)) {
- String connId = response.getString("connId");
- log.info("{}: WebSocket登录成功, connId: {}", account.name(), connId);
- subscribeAccountChannel(SUBSCRIBE);
- subscribeOrderInfoChannel(SUBSCRIBE);
- subscribePositionChannel(SUBSCRIBE);
- } else {
- log.error("{}: WebSocket登录失败, code: {}, msg: {}", account.name(), code, response.getString("msg"));
- }
- } else if ("subscribe".equals(event)) {
- subscribeEvent(response);
- } else if ("error".equals(event)) {
- log.error("{}: 订阅错误: code={}, msg={}",
- account.name(), response.getString("code"), response.getString("msg"));
- } else if ("channel-conn-count".equals(event)) {
- log.info("{}: 连接限制更新: channel={}, connCount={}",
- account.name(), response.getString("channel"), response.getString("connCount"));
- } else {
- processPushData(response);
- }
- } catch (Exception e) {
- log.error("{}: 处理WebSocket消息失败: {}", account.name(), message, e);
- }
- }
-
- private void subscribeEvent(JSONObject response) {
- JSONObject arg = response.getJSONObject("arg");
- if (arg == null) {
- log.warn("无效的推送数据,缺少 'arg' 字段 :{}",response);
- return;
- }
-
- String channel = arg.getString("channel");
- if (channel == null) {
- log.warn("无效的推送数据,缺少 'channel' 字段{}",response);
- return;
- }
- if (OrderInfoWs.ORDERINFOWS_CHANNEL.equals(channel)) {
- OrderInfoWs.initEvent(response, account.name());
- }
- if (AccountWs.ACCOUNTWS_CHANNEL.equals(channel)) {
- AccountWs.initEvent(response, account.name());
- }
- if (PositionsWs.POSITIONSWS_CHANNEL.equals(channel)) {
- PositionsWs.initEvent(response, account.name());
- }
- }
-
- /**
- * 解析并处理价格推送数据。
- * 将最新的标记价格存入 Redis 并触发后续业务逻辑比较处理。
- *
- * @param response 包含价格数据的 JSON 对象
- */
- private void processPushData(JSONObject response) {
- String op = response.getString("op");
- if (op != null){
- if (TradeOrderWs.ORDERWS_CHANNEL.equals(op)) {
- // 直接使用Object类型接收,避免强制类型转换
- Object data = response.get("data");
- log.info("{}: 收到下单推送结果: {}", account.name(), JSON.toJSONString(data));
- return;
- }
- }
- JSONObject arg = response.getJSONObject("arg");
- if (arg == null) {
- log.warn("{}: 无效的推送数据,缺少 'arg' 字段 :{}", account.name(), response);
- return;
- }
-
- String channel = arg.getString("channel");
- if (channel == null) {
- log.warn("{}: 无效的推送数据,缺少 'channel' 字段{}", account.name(), response);
- return;
- }
-
- // 注意:当前实现中,OrderInfoWs等类使用静态Map存储数据
- // 这会导致多账号之间的数据冲突。需要进一步修改这些类的设计,让数据存储与特定账号关联
- if (OrderInfoWs.ORDERINFOWS_CHANNEL.equals(channel)) {
-// OrderInfoWs.handleEvent(response, redisUtils, account.name());
- List<TradeRequestParam> tradeRequestParams = OrderInfoWs.handleEvent(response, redisUtils, account.name());
- TradeOrderWs.orderZhiYingZhiSunEventNoState(webSocketClient, tradeRequestParams);
- }else if (AccountWs.ACCOUNTWS_CHANNEL.equals(channel)) {
- AccountWs.handleEvent(response, account.name());
- } else if (PositionsWs.POSITIONSWS_CHANNEL.equals(channel)) {
- PositionsWs.handleEvent(response, account.name());
- } else if (BalanceAndPositionWs.CHANNEL_NAME.equals(channel)) {
- BalanceAndPositionWs.handleEvent(response);
- }
- }
-
- /**
- * 启动心跳检测任务。
- * 使用 ScheduledExecutorService 定期检查是否需要发送 ping 请求来维持连接。
- */
- private void startHeartbeat() {
- if (heartbeatExecutor != null && !heartbeatExecutor.isTerminated()) {
- heartbeatExecutor.shutdownNow();
- }
-
- heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
- Thread t = new Thread(r, "okx-account-order-heartbeat");
- t.setDaemon(true);
- return t;
- });
-
- heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout,
- HEARTBEAT_TIMEOUT, HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
- }
-
- // 移除了 schedulePeriodicReconnect 方法
-
- /**
- * 重置心跳计时器。
- * 当收到新消息或发送 ping 后取消当前超时任务并重新安排下一次超时检查。
- */
- private void resetHeartbeatTimer() {
- cancelPongTimeout();
-
- // 检查线程池状态,避免在关闭过程中提交任务
- if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) {
- pongTimeoutFuture = heartbeatExecutor.schedule(this::checkHeartbeatTimeout,
- HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
- }
- }
-
- // 移除了 performScheduledReconnect 方法
-
- /**
- * 检查心跳超时情况。
- * 若长时间未收到任何消息则主动发送 ping 请求保持连接活跃。
- */
- private void checkHeartbeatTimeout() {
- // 只有在连接状态下才检查心跳
- if (!isConnected.get()) {
- return;
- }
-
- long currentTime = System.currentTimeMillis();
- long lastTime = lastMessageTime.get();
-
- if (currentTime - lastTime >= HEARTBEAT_TIMEOUT * 1000L) {
- sendPing();
- }
- }
-
- /**
- * 发送 ping 请求至 WebSocket 服务端。
- * 用于维持长连接有效性。
- */
- private void sendPing() {
- try {
- if (webSocketClient != null && webSocketClient.isOpen()) {
- webSocketClient.send("ping");
- log.debug("发送ping请求");
- }
- } catch (Exception e) {
- log.warn("发送ping失败", e);
- }
- }
-
- /**
- * 取消当前的心跳超时任务。
- * 在收到 pong 或其他有效消息时调用此方法避免不必要的断开重连。
- */
- private void cancelPongTimeout() {
- if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) {
- pongTimeoutFuture.cancel(true);
- }
- }
-
- /**
- * 执行 WebSocket 重连操作。
- * 在连接意外中断后尝试重新建立连接。
- */
- private void reconnectWithBackoff() throws InterruptedException {
- // 如果正在连接,则不重复发起重连
- if (isConnecting.get()) {
- log.info("连接已在进行中,跳过重连请求");
- return;
- }
-
- int attempt = 0;
- int maxAttempts = 3;
- long delayMs = 1000;
-
- while (attempt < maxAttempts && !isConnected.get()) {
- try {
- Thread.sleep(delayMs);
- connect();
-
- // 等待连接建立
- for (int i = 0; i < 10 && isConnecting.get(); i++) {
- Thread.sleep(500);
- }
-
- if (isConnected.get()) {
- log.info("重连成功");
- return;
- }
- } catch (Exception e) {
- log.warn("第{}次重连失败", attempt + 1, e);
- delayMs *= 2;
- attempt++;
- }
- }
-
- log.error("超过最大重试次数({})仍未连接成功", maxAttempts);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java
new file mode 100644
index 0000000..d96dd44
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java
@@ -0,0 +1,383 @@
+package com.xcong.excoin.modules.okxNewPrice;
+
+import com.alibaba.fastjson.JSON;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OKXContants;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.LinkedHashMap;
+import java.util.concurrent.*;
+import java.util.function.Consumer;
+
+/**
+ * OKX REST API 异步执行器,所有下单/撤单操作经此类提交。
+ *
+ * <h3>设计目的</h3>
+ * REST API 调用可能耗时数百毫秒,若在 WebSocket 回调线程中同步执行会阻塞消息处理。
+ * 本类将所有网络 I/O 提交到独立单线程池异步执行。
+ *
+ * <h3>线程模型</h3>
+ * <ul>
+ * <li><b>单线程 + 有界队列(64)</b> — 保证下单顺序,避免并发竞争</li>
+ * <li><b>CallerRunsPolicy</b> — 队列满时由提交线程直接执行,形成自然背压</li>
+ * <li><b>Daemon 线程</b> — 60s 空闲自动回收</li>
+ * </ul>
+ *
+ * <h3>OKX API 适配说明</h3>
+ * OKX 使用 algo order(条件单)代替 Gate 的 FuturesPriceTriggeredOrder:
+ * <ul>
+ * <li>开仓条件单:ordType=conditional, side=buy/sell, posSide=long/short</li>
+ * <li>止盈止损单:可通过订单附带的 tpTriggerPx/slTriggerPx 或单独的 algo order 实现</li>
+ * <li>市价单:ordType=market, price不传</li>
+ * </ul>
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class OkxTradeExecutor {
+
+ /** OKX 账户配置(用于 REST API 调用) */
+ private final OKXAccount okxAccount;
+ /** 合约名称(如 ETH-USDT-SWAP) */
+ private final String instId;
+ /** 保证金模式 */
+ private final String tdMode;
+
+ /** 交易线程池:单线程 + 有界队列 + 背压策略 */
+ private final ExecutorService executor;
+
+ public OkxTradeExecutor(OKXAccount okxAccount, String instId, String tdMode) {
+ this.okxAccount = okxAccount;
+ this.instId = instId;
+ this.tdMode = tdMode;
+ this.executor = new ThreadPoolExecutor(
+ 1, 1,
+ 60L, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<>(64),
+ r -> {
+ Thread t = new Thread(r, "okx-trade-worker");
+ t.setDaemon(true);
+ return t;
+ },
+ new ThreadPoolExecutor.CallerRunsPolicy()
+ );
+ ((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true);
+ }
+
+ /**
+ * 优雅关闭:等待 10 秒让队列中的任务执行完毕,超时则强制中断。
+ */
+ public void shutdown() {
+ executor.shutdown();
+ try {
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ executor.shutdownNow();
+ }
+ }
+
+ /**
+ * 异步 IOC 市价开多。
+ *
+ * @param quantity 开仓张数(正数)
+ * @param onSuccess 成功回调,接收 orderId
+ * @param onFailure 失败回调
+ */
+ public void openLong(String quantity, Consumer<String> onSuccess, Runnable onFailure) {
+ submitOrder("buy", "long", quantity, "market", null, false, "t-okx-grid-long", onSuccess, onFailure);
+ }
+
+ /**
+ * 异步 IOC 市价开空。
+ *
+ * @param quantity 开仓张数(正数)
+ * @param onSuccess 成功回调,接收 orderId
+ * @param onFailure 失败回调
+ */
+ public void openShort(String quantity, Consumer<String> onSuccess, Runnable onFailure) {
+ submitOrder("sell", "short", quantity, "market", null, false, "t-okx-grid-short", onSuccess, onFailure);
+ }
+
+ /**
+ * 异步市价平仓(reduceOnly=true)。
+ *
+ * @param side "buy" 平空 / "sell" 平多
+ * @param posSide "long" / "short"
+ * @param quantity 平仓张数(正数)
+ */
+ public void marketClose(String side, String posSide, String quantity) {
+ executor.execute(() -> {
+ try {
+ LinkedHashMap<String, Object> params = buildBaseParams(side, posSide, quantity, "market");
+ params.put("reduceOnly", true);
+ String resp = okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, OKXContants.ORDER, params, HttpMethod.POST, okxAccount.isSimluate());
+ log.info("[OkxExec] 市价平仓成功, side:{}, posSide:{}, sz:{}, resp:{}", side, posSide, quantity, resp);
+ } catch (Exception e) {
+ log.error("[OkxExec] 市价平仓失败, side:{}, posSide:{}, sz:{}", side, posSide, quantity, e);
+ }
+ });
+ }
+
+ /**
+ * 异步创建条件开仓单(价格触发后市价开仓)。
+ * OKX 使用 algo order: /api/v5/trade/order-algo, ordType=conditional
+ *
+ * @param triggerPrice 触发价格
+ * @param side "buy" 开多 / "sell" 开空
+ * @param posSide "long" / "short"
+ * @param size 开仓张数
+ * @param onSuccess 成功回调,接收 algoId
+ * @param onFailure 失败回调
+ */
+ public void placeConditionalEntryOrder(String triggerPrice, String side, String posSide,
+ String size, Consumer<String> onSuccess, Runnable onFailure) {
+ executor.execute(() -> {
+ try {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("instId", instId);
+ params.put("tdMode", tdMode);
+ params.put("side", side);
+ params.put("posSide", posSide);
+ params.put("ordType", "conditional");
+ params.put("sz", size);
+ params.put("triggerPx", triggerPrice);
+ params.put("triggerPxType", "last");
+ params.put("orderPx", "-1"); // 市价成交
+
+ String resp = okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, "/api/v5/trade/order-algo", params, HttpMethod.POST, okxAccount.isSimluate());
+ log.info("[OkxExec] 条件开仓单已创建, trigger:{}, side:{}, posSide:{}, sz:{}, resp:{}",
+ triggerPrice, side, posSide, size, resp);
+
+ String algoId = parseAlgoId(resp);
+ if (algoId != null && onSuccess != null) {
+ onSuccess.accept(algoId);
+ }
+ } catch (Exception e) {
+ log.error("[OkxExec] 条件开仓单创建失败, trigger:{}, side:{}, sz:{}", triggerPrice, side, size, e);
+ if (onFailure != null) {
+ onFailure.run();
+ }
+ }
+ });
+ }
+
+ /**
+ * 异步创建止盈条件单。
+ * 使用 algo order: ordType=conditional, 触发后市价平仓 (reduceOnly=true)
+ *
+ * @param triggerPrice 止盈触发价
+ * @param side "sell" 平多 / "buy" 平空
+ * @param posSide "long" / "short"
+ * @param size 平仓张数
+ * @param onSuccess 成功回调,接收 algoId
+ */
+ public void placeTakeProfit(String triggerPrice, String side, String posSide,
+ String size, Consumer<String> onSuccess) {
+ executor.execute(() -> {
+ try {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("instId", instId);
+ params.put("tdMode", tdMode);
+ params.put("side", side);
+ params.put("posSide", posSide);
+ params.put("ordType", "conditional");
+ params.put("sz", size);
+ params.put("triggerPx", triggerPrice);
+ params.put("triggerPxType", "last");
+ params.put("orderPx", "-1"); // 市价成交
+
+ String resp = okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, "/api/v5/trade/order-algo", params, HttpMethod.POST, okxAccount.isSimluate());
+ log.info("[OkxExec] 止盈单已创建, trigger:{}, side:{}, posSide:{}, sz:{}, resp:{}",
+ triggerPrice, side, posSide, size, resp);
+
+ String algoId = parseAlgoId(resp);
+ if (algoId != null && onSuccess != null) {
+ onSuccess.accept(algoId);
+ }
+ } catch (Exception e) {
+ log.error("[OkxExec] 止盈单创建失败, trigger:{}, side:{}, sz:{}, 立即市价止盈",
+ triggerPrice, side, size, e);
+ // 止盈单创建失败 → 立即市价平仓
+ marketClose(side, posSide, size);
+ }
+ });
+ }
+
+ /**
+ * 异步取消单个条件单(algo order)。
+ *
+ * @param algoId 条件单 ID,为 null 时跳过
+ */
+ public void cancelAlgoOrder(String algoId, Consumer<String> onSuccess) {
+ if (algoId == null) {
+ return;
+ }
+ executor.execute(() -> {
+ try {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("instId", instId);
+ params.put("algoId", algoId);
+ String resp = okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, "/api/v5/trade/cancel-algos", params, HttpMethod.POST, okxAccount.isSimluate());
+ log.info("[OkxExec] 条件单已取消, algoId:{}", algoId);
+ if (onSuccess != null) {
+ onSuccess.accept(algoId);
+ }
+ } catch (Exception e) {
+ log.warn("[OkxExec] 取消条件单失败(可能已触发), algoId:{}", algoId);
+ }
+ });
+ }
+
+ /**
+ * 异步取消所有未完成的 algo 订单。
+ */
+ public void cancelAllAlgoOrders() {
+ executor.execute(() -> {
+ try {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("instId", instId);
+ String resp = okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, "/api/v5/trade/cancel-algos", params, HttpMethod.POST, okxAccount.isSimluate());
+ log.info("[OkxExec] 已尝试清除条件单, resp:{}", resp);
+ } catch (Exception e) {
+ log.error("[OkxExec] 清除条件单失败", e);
+ }
+ });
+ }
+
+ /**
+ * 查询账户余额(同步方法,在策略线程中调用)。
+ */
+ public String getBalance() {
+ try {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("ccy", "USDT");
+ return okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, OKXContants.BALANCE, params, HttpMethod.GET, okxAccount.isSimluate());
+ } catch (Exception e) {
+ log.error("[OkxExec] 查询余额失败", e);
+ return null;
+ }
+ }
+
+ /**
+ * 查询持仓信息(同步方法)。
+ */
+ public String getPositions() {
+ try {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("instId", instId);
+ return okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, OKXContants.POSITIONS, params, HttpMethod.GET, okxAccount.isSimluate());
+ } catch (Exception e) {
+ log.error("[OkxExec] 查询持仓失败", e);
+ return null;
+ }
+ }
+
+ /**
+ * 设置杠杆倍数(同步方法)。
+ */
+ public void setLeverage(String leverage) {
+ try {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("instId", instId);
+ params.put("lever", leverage);
+ params.put("mgnMode", tdMode);
+ String resp = okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, OKXContants.SETLEVERAGE, params, HttpMethod.POST, okxAccount.isSimluate());
+ log.info("[OkxExec] 设置杠杆成功, lever:{}, resp:{}", leverage, resp);
+ } catch (Exception e) {
+ log.error("[OkxExec] 设置杠杆失败, lever:{}", leverage, e);
+ }
+ }
+
+ // ==================== 私有方法 ====================
+
+ private LinkedHashMap<String, Object> buildBaseParams(String side, String posSide, String sz, String ordType) {
+ LinkedHashMap<String, Object> params = new LinkedHashMap<>();
+ params.put("instId", instId);
+ params.put("tdMode", tdMode);
+ params.put("side", side);
+ params.put("posSide", posSide);
+ params.put("ordType", ordType);
+ params.put("sz", sz);
+ return params;
+ }
+
+ private void submitOrder(String side, String posSide, String quantity, String ordType,
+ String price, boolean reduceOnly, String tag,
+ Consumer<String> onSuccess, Runnable onFailure) {
+ executor.execute(() -> {
+ try {
+ LinkedHashMap<String, Object> params = buildBaseParams(side, posSide, quantity, ordType);
+ if (price != null) {
+ params.put("px", price);
+ }
+ if (reduceOnly) {
+ params.put("reduceOnly", true);
+ }
+ if (tag != null) {
+ params.put("tag", tag);
+ }
+ String resp = okxAccount.requestHandler.sendSignedRequest(
+ okxAccount.baseUrl, OKXContants.ORDER, params, HttpMethod.POST, okxAccount.isSimluate());
+ log.info("[OkxExec] 下单成功, side:{}, posSide:{}, sz:{}, ordType:{}, resp:{}",
+ side, posSide, quantity, ordType, resp);
+
+ String orderId = parseOrderId(resp);
+ if (orderId != null && onSuccess != null) {
+ onSuccess.accept(orderId);
+ }
+ } catch (Exception e) {
+ log.error("[OkxExec] 下单失败, side:{}, posSide:{}, sz:{}", side, posSide, quantity, e);
+ if (onFailure != null) {
+ onFailure.run();
+ }
+ }
+ });
+ }
+
+ /**
+ * 从 OKX 响应中解析订单 ID。
+ * 响应格式: {"code":"0","data":[{"ordId":"xxx",...}]}
+ */
+ private String parseOrderId(String resp) {
+ try {
+ com.alibaba.fastjson.JSONObject json = JSON.parseObject(resp);
+ if ("0".equals(json.getString("code"))) {
+ com.alibaba.fastjson.JSONArray data = json.getJSONArray("data");
+ if (data != null && !data.isEmpty()) {
+ return data.getJSONObject(0).getString("ordId");
+ }
+ }
+ } catch (Exception e) {
+ log.warn("[OkxExec] 解析订单ID失败, resp:{}", resp);
+ }
+ return null;
+ }
+
+ /**
+ * 从 OKX 响应中解析 algo 订单 ID。
+ */
+ private String parseAlgoId(String resp) {
+ try {
+ com.alibaba.fastjson.JSONObject json = JSON.parseObject(resp);
+ if ("0".equals(json.getString("code"))) {
+ com.alibaba.fastjson.JSONArray data = json.getJSONArray("data");
+ if (data != null && !data.isEmpty()) {
+ return data.getJSONObject(0).getString("algoId");
+ }
+ }
+ } catch (Exception e) {
+ log.warn("[OkxExec] 解析algoId失败, resp:{}", resp);
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTraderParam.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTraderParam.java
new file mode 100644
index 0000000..2cacad0
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTraderParam.java
@@ -0,0 +1,102 @@
+package com.xcong.excoin.modules.okxNewPrice;
+
+import java.math.BigDecimal;
+
+/**
+ * 单笔挂单的完整参数,封装条件开仓单及止盈单的状态。
+ *
+ * <h3>定位</h3>
+ * 每个 OkxGridElement 内嵌两个 OkxTraderParam(longTraderParam / shortTraderParam),
+ * 分别记录该价格层级上多仓和空仓的挂单参数。
+ *
+ * <h3>字段分组</h3>
+ * <table>
+ * <tr><th>类别</th><th>字段</th><th>生命周期</th></tr>
+ * <tr><td>开仓准备</td><td>direction, entryPrice, quantity</td><td>updateGridElements() 预填充</td></tr>
+ * <tr><td>止盈预定</td><td>takeProfitPrice</td><td>updateGridElements() 预填充</td></tr>
+ * <tr><td>挂单确认</td><td>entryOrderPlaced, entryOrderId</td><td>条件单挂成功后写入</td></tr>
+ * <tr><td>止盈确认</td><td>takeProfitPlaced, takeProfitOrderId</td><td>止盈单挂成功后写入</td></tr>
+ * </table>
+ *
+ * @author Administrator
+ */
+public class OkxTraderParam {
+
+ public enum Direction {
+ LONG,
+ SHORT
+ }
+
+ /** 交易方向 */
+ private Direction direction;
+ /** 下单数量(合约张数) */
+ private String quantity;
+ /** 条件开仓触发价 */
+ private BigDecimal entryPrice;
+ /** 挂单(条件开仓单)订单 ID */
+ private String entryOrderId;
+ /** 挂单价是否挂成功 */
+ private boolean entryOrderPlaced;
+ /** 止盈触发价 */
+ private BigDecimal takeProfitPrice;
+ /** 止盈条件单(算法单)订单 ID(OKX 用 algoId) */
+ private String takeProfitOrderId;
+ /** 止盈价是否挂成功 */
+ private boolean takeProfitPlaced;
+
+ private OkxTraderParam(Builder builder) {
+ this.direction = builder.direction;
+ this.entryPrice = builder.entryPrice;
+ this.takeProfitPrice = builder.takeProfitPrice;
+ this.quantity = builder.quantity;
+ this.takeProfitPlaced = builder.takeProfitPlaced;
+ this.entryOrderPlaced = builder.entryOrderPlaced;
+ this.takeProfitOrderId = builder.takeProfitOrderId;
+ this.entryOrderId = builder.entryOrderId;
+ }
+
+ public Direction getDirection() { return direction; }
+ public void setDirection(Direction direction) { this.direction = direction; }
+ public BigDecimal getEntryPrice() { return entryPrice; }
+ public void setEntryPrice(BigDecimal entryPrice) { this.entryPrice = entryPrice; }
+ public BigDecimal getTakeProfitPrice() { return takeProfitPrice; }
+ public void setTakeProfitPrice(BigDecimal takeProfitPrice) { this.takeProfitPrice = takeProfitPrice; }
+ public String getQuantity() { return quantity; }
+ public void setQuantity(String quantity) { this.quantity = quantity; }
+ public String getEntryOrderId() { return entryOrderId; }
+ public void setEntryOrderId(String entryOrderId) { this.entryOrderId = entryOrderId; }
+ public boolean isEntryOrderPlaced() { return entryOrderPlaced; }
+ public void setEntryOrderPlaced(boolean entryOrderPlaced) { this.entryOrderPlaced = entryOrderPlaced; }
+ public boolean isTakeProfitPlaced() { return takeProfitPlaced; }
+ public void setTakeProfitPlaced(boolean takeProfitPlaced) { this.takeProfitPlaced = takeProfitPlaced; }
+ public String getTakeProfitOrderId() { return takeProfitOrderId; }
+ public void setTakeProfitOrderId(String takeProfitOrderId) { this.takeProfitOrderId = takeProfitOrderId; }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private Direction direction;
+ private BigDecimal entryPrice;
+ private BigDecimal takeProfitPrice;
+ private String quantity = "1";
+ private boolean takeProfitPlaced = false;
+ private boolean entryOrderPlaced = false;
+ private String takeProfitOrderId;
+ private String entryOrderId;
+
+ public Builder direction(Direction direction) { this.direction = direction; return this; }
+ public Builder entryPrice(BigDecimal entryPrice) { this.entryPrice = entryPrice; return this; }
+ public Builder takeProfitPrice(BigDecimal takeProfitPrice) { this.takeProfitPrice = takeProfitPrice; return this; }
+ public Builder quantity(String quantity) { this.quantity = quantity; return this; }
+ public Builder takeProfitPlaced(boolean takeProfitPlaced) { this.takeProfitPlaced = takeProfitPlaced; return this; }
+ public Builder entryOrderPlaced(boolean entryOrderPlaced) { this.entryOrderPlaced = entryOrderPlaced; return this; }
+ public Builder takeProfitOrderId(String takeProfitOrderId) { this.takeProfitOrderId = takeProfitOrderId; return this; }
+ public Builder entryOrderId(String entryOrderId) { this.entryOrderId = entryOrderId; return this; }
+
+ public OkxTraderParam build() {
+ return new OkxTraderParam(this);
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientMain.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientMain.java
deleted file mode 100644
index 9eebd2d..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientMain.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice;
-
-import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoServiceImpl;
-import com.xcong.excoin.modules.okxNewPrice.wangge.WangGeServiceImpl;
-import com.xcong.excoin.utils.RedisUtils;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-public class OkxWebSocketClientMain {
- public static void main(String[] args) throws InterruptedException {
- // 使用Spring上下文初始化管理器
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- OkxWebSocketClientManager manager = context.getBean(OkxWebSocketClientManager.class);
-
- // 运行一段时间以观察结果
- Thread.sleep(1200000000L); // 运行一小时
-
- // 关闭连接
- manager.destroy();
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientManager.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientManager.java
index c00f893..10fcdd3 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientManager.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxWebSocketClientManager.java
@@ -1,132 +1,153 @@
package com.xcong.excoin.modules.okxNewPrice;
-import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.ExchangeInfoEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListService;
-import com.xcong.excoin.utils.RedisUtils;
+import com.xcong.excoin.modules.okxNewPrice.gridWs.OkxAlgoOrdersChannelHandler;
+import com.xcong.excoin.modules.okxNewPrice.gridWs.OkxKlineChannelHandler;
+import com.xcong.excoin.modules.okxNewPrice.gridWs.OkxPositionsChannelHandler;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.DefaultUrls;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
+import java.math.BigDecimal;
/**
- * 管理多个OKX WebSocket客户端实例,每个实例对应一个账号
+ * OKX 网格交易系统 Spring 容器入口 — 组件组装 + 生命周期管理。
+ *
+ * <h3>组装顺序({@code @PostConstruct})</h3>
+ * <ol>
+ * <li>{@link OkxConfig} — 构建配置(API 密钥、合约、策略参数)</li>
+ * <li>{@link OkxGridTradeService}.init() — 获取账户 → 清条件单 → 平仓 → 设杠杆</li>
+ * <li>{@link OkxGridWsClient} — 注册 3 个频道处理器 → init():建立 WS 连接并登录订阅</li>
+ * <li>{@code gridTradeService.startGrid()} — 状态重置,等待首根 K 线</li>
+ * </ol>
+ *
+ * <h3>3 个频道处理器</h3>
+ * <ol>
+ * <li>OkxKlineChannelHandler — candle1m,K线 → onKline()</li>
+ * <li>OkxPositionsChannelHandler — positions,持仓 → onPositionUpdate()</li>
+ * <li>OkxAlgoOrdersChannelHandler — orders-algo,条件单 → onOrderUpdate()</li>
+ * </ol>
+ *
+ * <h3>销毁顺序({@code @PreDestroy})</h3>
+ * <ol>
+ * <li>gridTradeService.stopGrid():取消所有条件单 → 关闭交易线程池</li>
+ * <li>gridWsClient.destroy():取消订阅 → 断开 WS → 关闭线程池</li>
+ * </ol>
+ *
+ * @author Administrator
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "app", name = "quant", havingValue = "true")
public class OkxWebSocketClientManager {
- @Autowired
- private CaoZuoService caoZuoService;
- @Autowired
- private RedisUtils redisUtils;
- @Autowired
- private WangGeListService wangGeListService;
- // 存储所有OkxQuantWebSocketClient实例,key为账号类型名称
- private final Map<String, OkxQuantWebSocketClient> quantClientMap = new ConcurrentHashMap<>();
-
- // 存储OkxNewPriceWebSocketClient实例
- private OkxKlineWebSocketClient klinePriceClient;
+ /** 网格交易 WS 客户端 */
+ private OkxGridWsClient gridWsClient;
+ /** 网格交易策略服务 */
+ private OkxGridTradeService gridTradeService;
+ /** 统一配置 */
+ private OkxConfig okxConfig;
-
- /**
- * 初始化方法,在Spring Bean构造完成后执行
- * 创建并初始化所有账号的WebSocket客户端实例
- */
@PostConstruct
public void init() {
- log.info("开始初始化OkxWebSocketClientManager");
-
- // 初始化价格WebSocket客户端
+ log.info("[OKX-Manager] 开始初始化...");
+
try {
- klinePriceClient = new OkxKlineWebSocketClient(redisUtils, caoZuoService, this, wangGeListService);
- klinePriceClient.init();
- log.info("已初始化OkxNewPriceWebSocketClient");
- } catch (Exception e) {
- log.error("初始化OkxNewPriceWebSocketClient失败", e);
- }
-
- // 获取所有ExchangeInfoEnum枚举值
- ExchangeInfoEnum[] accounts = ExchangeInfoEnum.values();
-
- // 为每个账号创建一个WebSocket客户端实例
- for (ExchangeInfoEnum account : accounts) {
- try {
- OkxQuantWebSocketClient client = new OkxQuantWebSocketClient(account, caoZuoService, redisUtils);
- quantClientMap.put(account.name(), client);
- client.init();
- log.info("已初始化账号 {} 的WebSocket客户端", account.name());
- } catch (Exception e) {
- log.error("初始化账号 {} 的WebSocket客户端失败", account.name(), e);
+ // 获取账户配置
+ ExchangeInfoEnum[] accounts = ExchangeInfoEnum.values();
+ if (accounts == null || accounts.length == 0) {
+ log.error("[OKX-Manager] 无可用账户,初始化失败");
+ return;
}
+
+ // 使用第一个账户
+ ExchangeInfoEnum primaryAccount = accounts[0];
+ log.info("[OKX-Manager] 使用主账户: {}", primaryAccount.name());
+
+ // 1. 创建 OKXAccount(REST API 调用需要)
+ String baseUrl = primaryAccount.isAccountType() ? DefaultUrls.USDM_PROD_URL : DefaultUrls.USDM_UAT_URL;
+ OKXAccount okxAccount = new OKXAccount(
+ baseUrl,
+ primaryAccount.getApiKey(),
+ primaryAccount.getSecretKey(),
+ primaryAccount.getPassphrase(),
+ !primaryAccount.isAccountType()
+ );
+
+ // 2. 构建 OkxConfig
+ // TODO: 参数可通过配置文件/数据库动态读取
+ okxConfig = OkxConfig.builder()
+ .apiKey(primaryAccount.getApiKey())
+ .secretKey(primaryAccount.getSecretKey())
+ .passphrase(primaryAccount.getPassphrase())
+ .instId("ETH-USDT-SWAP")
+ .leverage("100")
+ .tdMode("cross")
+ .gridRate(new BigDecimal("0.0025"))
+ .expectedProfit(new BigDecimal("2"))
+ .maxLoss(new BigDecimal("15"))
+ .quantity("1")
+ .baseQuantity("10")
+ .priceScale(2)
+ .ctVal(new BigDecimal("0.1"))
+ .isSimulate(!primaryAccount.isAccountType())
+ .gridQueueSize(300)
+ .marginRatioLimit(new BigDecimal("0.2"))
+ .build();
+
+ // 3. 初始化交易服务:查账户 → 清条件单 → 平已有仓位 → 设杠杆
+ gridTradeService = new OkxGridTradeService(okxConfig, okxAccount);
+ gridTradeService.init();
+
+ // 4. 创建 WS 客户端并注册 3 个频道处理器
+ gridWsClient = new OkxGridWsClient(primaryAccount);
+ gridWsClient.addChannelHandler(new OkxKlineChannelHandler(okxConfig.getInstId(), gridTradeService));
+ gridWsClient.addChannelHandler(new OkxPositionsChannelHandler(okxConfig.getInstId(), gridTradeService));
+ gridWsClient.addChannelHandler(new OkxAlgoOrdersChannelHandler(okxConfig.getInstId(), gridTradeService));
+ gridWsClient.init();
+ log.info("[OKX-Manager] WS已连接, 已注册 3 个频道处理器: candle1m/positions/orders-algo");
+
+ // 5. 激活策略,等待首根 K 线触发基底双开
+ gridTradeService.startGrid();
+
+ log.info("[OKX-Manager] 初始化完成");
+ } catch (Exception e) {
+ log.error("[OKX-Manager] 初始化失败", e);
}
-
- log.info("OkxWebSocketClientManager初始化完成");
}
/**
- * 销毁方法,在Spring Bean销毁前执行
- * 关闭所有WebSocket客户端连接和相关资源
+ * 销毁:停止策略 → 关闭交易线程池 → 取消 WS 订阅 → 断开连接 → 关闭 WS 线程池。
*/
@PreDestroy
public void destroy() {
- log.info("开始销毁OkxWebSocketClientManager");
-
- // 关闭价格WebSocket客户端
- if (klinePriceClient != null) {
+ log.info("[OKX-Manager] 开始销毁...");
+
+ if (gridTradeService != null) {
try {
- klinePriceClient.destroy();
- log.info("已销毁OkxNewPriceWebSocketClient");
+ gridTradeService.stopGrid();
} catch (Exception e) {
- log.error("销毁OkxNewPriceWebSocketClient失败", e);
+ log.error("[OKX-Manager] 停止策略失败", e);
}
}
-
- // 关闭所有量化交易WebSocket客户端实例
- for (Map.Entry<String, OkxQuantWebSocketClient> entry : quantClientMap.entrySet()) {
+ if (gridWsClient != null) {
try {
- OkxQuantWebSocketClient client = entry.getValue();
- client.destroy();
- log.info("已销毁账号 {} 的WebSocket客户端", entry.getKey());
+ gridWsClient.destroy();
} catch (Exception e) {
- log.error("销毁账号 {} 的WebSocket客户端失败", entry.getKey(), e);
+ log.error("[OKX-Manager] 销毁WS客户端失败", e);
}
}
-
- // 清空客户端映射
- quantClientMap.clear();
-
- log.info("OkxWebSocketClientManager销毁完成");
+
+ log.info("[OKX-Manager] 销毁完成");
}
- /**
- * 获取指定账号的OkxQuantWebSocketClient实例
- * @param accountName 账号类型名称
- * @return WebSocket客户端实例
- */
- public OkxQuantWebSocketClient getClient(String accountName) {
- return quantClientMap.get(accountName);
- }
-
- /**
- * 获取所有OkxQuantWebSocketClient实例
- * @return 所有客户端实例的集合
- */
- public Collection<OkxQuantWebSocketClient> getAllClients() {
- return quantClientMap.values();
- }
-
- /**
- * 获取OkxNewPriceWebSocketClient实例
- * @return 价格WebSocket客户端实例
- */
- public OkxKlineWebSocketClient getKlineWebSocketClient() {
- return klinePriceClient;
- }
-}
\ No newline at end of file
+ /** @return 网格交易策略服务实例 */
+ public OkxGridTradeService getGridTradeService() { return gridTradeService; }
+ /** @return 网格交易 WS 客户端实例 */
+ public OkxGridWsClient getGridWsClient() { return gridWsClient; }
+ /** @return 统一配置实例 */
+ public OkxConfig getOkxConfig() { return okxConfig; }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/README.md b/src/main/java/com/xcong/excoin/modules/okxNewPrice/README.md
deleted file mode 100644
index cb6e715..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/README.md
+++ /dev/null
@@ -1,285 +0,0 @@
-# OKX 新价格量化交易模块文档
-
-## 1. 包结构
-
-```
-okxNewPrice/
-├── celue/ # 策略层
-│ ├── CaoZuoService.java # 操作服务接口
-│ └── CaoZuoServiceImpl.java # 操作服务实现
-├── jiaoyi/ # 交易层
-│ ├── IMQService.java # 消息队列服务接口
-│ └── IMQServiceImpl.java # 消息队列服务实现
-├── okxWs/ # OKX WebSocket 处理层
-│ ├── enums/ # WebSocket 相关枚举
-│ │ ├── CoinEnums.java # 币相关枚举
-│ │ ├── ExchangeInfoEnum.java # 交易所信息枚举
-│ │ └── OrderParamEnums.java # 订单参数枚举
-│ ├── wanggeList/ # 网格列表相关
-│ │ ├── WangGeListEnum.java # 网格枚举
-│ │ ├── WangGeListQueue.java # 网格队列
-│ │ ├── WangGeListService.java # 网格服务接口
-│ │ └── WangGeListServiceImpl.java # 网格服务实现
-│ ├── AccountWs.java # 账户信息处理
-│ ├── BalanceAndPositionWs.java # 余额和持仓处理
-│ ├── InstrumentsWs.java # 合约信息处理
-│ ├── LoginWs.java # 登录处理
-│ ├── OrderInfoWs.java # 订单信息处理
-│ ├── PositionsWs.java # 持仓信息处理
-│ └── TradeOrderWs.java # 交易订单处理
-├── okxpi/ # OKX API 相关
-│ ├── config/ # 配置相关
-│ ├── enumerates/ # 枚举
-│ ├── order/ # 订单相关
-│ ├── query/ # 查询相关
-│ ├── trade/ # 交易相关
-│ ├── verify/ # 验证相关
-│ └── ... # 其他API工具类
-├── utils/ # 工具类
-│ ├── FebsException.java # 异常类
-│ ├── FebsResponse.java # 响应类
-│ ├── SSLConfig.java # SSL配置
-│ ├── SignUtils.java # 签名工具
-│ ├── WsMapBuild.java # WebSocket Map构建工具
-│ └── WsParamBuild.java # WebSocket 参数构建工具
-├── wangge/ # 网格相关
-│ ├── WangGeEnum.java # 网格枚举
-│ ├── WangGeQueue.java # 网格队列
-│ ├── WangGeService.java # 网格服务接口
-│ └── WangGeServiceImpl.java # 网格服务实现
-├── zhanghu/ # 账户相关
-│ ├── ApiMessageServiceImpl.java # API消息服务实现
-│ ├── IApiMessageService.java # API消息服务接口
-│ └── ZhangHuEnum.java # 账户枚举
-├── OkxNewPriceWebSocketClient.java # 价格WebSocket客户端
-├── OkxQuantWebSocketClient.java # 量化WebSocket客户端
-├── OkxWebSocketClientMain.java # WebSocket客户端主类
-└── OkxWebSocketClientManager.java # WebSocket客户端管理器
-```
-
-## 2. 核心组件说明
-
-### 2.1 WebSocket 客户端管理
-
-#### OkxWebSocketClientManager
-- **作用**:统一管理所有 OKX WebSocket 客户端实例
-- **核心功能**:
- - 初始化价格 WebSocket 客户端和多账号量化客户端
- - 提供客户端的获取和销毁功能
- - 管理客户端生命周期
-- **关键方法**:
- - `init()`:初始化所有客户端
- - `destroy()`:销毁所有客户端
- - `getAllClients()`:获取所有量化客户端实例
-
-#### OkxNewPriceWebSocketClient
-- **作用**:价格 WebSocket 客户端,负责获取实时价格数据
-- **核心功能**:
- - 连接 OKX 公共 WebSocket 接口获取标记价格
- - 将价格数据保存到 Redis
- - 价格变化时触发量化操作
- - 支持心跳检测和自动重连
-- **关键方法**:
- - `init()`:初始化客户端
- - `destroy()`:销毁客户端
- - `processPushData()`:处理价格推送数据
- - `triggerQuantOperations()`:触发所有账号的量化操作
-
-#### OkxQuantWebSocketClient
-- **作用**:量化交易 WebSocket 客户端,每个账号对应一个实例
-- **核心功能**:
- - 连接 OKX 私有 WebSocket 接口
- - 处理账户、持仓、订单等私有数据
- - 支持多账号独立操作
- - 支持心跳检测和自动重连
-- **关键方法**:
- - `init()`:初始化客户端
- - `destroy()`:销毁客户端
- - `websocketLogin()`:登录 WebSocket
- - `subscribeChannels()`:订阅相关频道
-
-### 2.2 策略层
-
-#### CaoZuoService
-- **作用**:交易策略服务接口
-- **核心功能**:
- - 决定是否进行交易操作
- - 根据价格和网格信息决定交易方向
- - 处理多头和空头策略
-
-#### CaoZuoServiceImpl
-- **作用**:交易策略服务实现类
-- **核心功能**:
- - 检查账户和持仓状态
- - 根据当前价格获取对应的网格
- - 实现多头和空头的具体交易逻辑
- - 管理网格队列和交易决策
-- **关键方法**:
- - `caoZuo()`:主交易逻辑
- - `caoZuoLong()`:多头交易逻辑
- - `caoZuoShort()`:空头交易逻辑
-
-### 2.3 网格策略
-
-#### WangGeListEnum
-- **作用**:网格数据枚举,定义不同价格区间的网格参数
-- **核心参数**:
- - `name`:网格名称
- - `jiage_shangxian`:价格上限
- - `jiage_xiaxian`:价格下限
- - `jian_ju`:网格间距
- - `fang_xiang`:交易方向(long/short)
-- **关键方法**:
- - `getGridByPrice()`:根据价格获取对应的网格
-
-#### WangGeListService
-- **作用**:网格服务接口,提供网格相关操作
-- **核心功能**:
- - 初始化网格队列
- - 管理网格的开仓和平仓队列
-
-### 2.4 持仓管理
-
-#### PositionsWs
-- **作用**:持仓信息处理类
-- **核心功能**:
- - 管理持仓数据(双层 Map 结构:账号_方向 -> 数据)
- - 提供持仓数据的获取和更新方法
- - 支持多账号多方向持仓管理
-- **关键方法**:
- - `initAccountName()`:初始化带方向的账号名
- - `handleEvent()`:处理持仓数据推送
- - `getAccountMap()`:获取指定账号的持仓数据
-
-## 3. 工作流程
-
-### 3.1 系统初始化流程
-
-1. **客户端初始化**:
- - Spring 容器启动时,`OkxWebSocketClientManager` 自动初始化
- - 创建并初始化 `OkxNewPriceWebSocketClient` 实例
- - 为每个账号创建并初始化 `OkxQuantWebSocketClient` 实例
-
-2. **WebSocket 连接**:
- - `OkxNewPriceWebSocketClient` 连接公共价格 WebSocket
- - 每个 `OkxQuantWebSocketClient` 连接私有 WebSocket 并登录
- - 订阅相关频道(价格、账户、持仓、订单等)
-
-### 3.2 价格触发交易流程
-
-```
-┌─────────────────────────┐ ┌─────────────────────────┐
-│ OkxNewPriceWebSocketClient │ │ WangGeListEnum │
-│ └─ processPushData() │────▶│ └─ getGridByPrice() │
-└─────────────────────────┘ └─────────────────────────┘
- ▲ ▼
- │ ┌─────────────────────────┐
- │ │ CaoZuoServiceImpl │
- │ │ └─ caoZuo() │
- │ └─────────────────────────┘
- │ ▼
- │ ┌─────────────────────────┐
- │ │ TradeOrderWs │
- │ │ └─ orderEvent() │
- │ └─────────────────────────┘
- │ ▼
-┌────────┴─────────────────────────────────────────────┐
-│ OkxQuantWebSocketClient │
-│ └─ handleWebSocketMessage() │
-└──────────────────────────────────────────────────────┘
-```
-
-1. **价格接收**:
- - `OkxNewPriceWebSocketClient` 接收实时价格推送
- - 调用 `processPushData()` 处理价格数据
-
-2. **策略决策**:
- - 根据当前价格获取对应的网格参数(`WangGeListEnum.getGridByPrice()`)
- - 调用 `CaoZuoServiceImpl.caoZuo()` 进行策略决策
- - 根据网格方向调用对应的多头或空头策略
-
-3. **订单执行**:
- - 调用 `TradeOrderWs.orderEvent()` 执行交易订单
- - 通过 `OkxQuantWebSocketClient` 发送订单指令
-
-### 3.3 持仓数据管理流程
-
-1. **数据接收**:
- - `OkxQuantWebSocketClient` 接收持仓数据推送
- - 调用 `PositionsWs.handleEvent()` 处理持仓数据
-
-2. **数据存储**:
- - 使用双层 Map 存储持仓数据:`accountName_posSide -> data`
- - 支持多头和空头方向的独立存储
-
-3. **数据使用**:
- - 策略层通过 `PositionsWs.getAccountMap()` 获取持仓数据
- - 根据持仓数据和当前价格决定交易操作
-
-## 4. 关键特性
-
-### 4.1 多网格策略
-
-- **实现方式**:通过 `WangGeListEnum` 定义多个价格区间的网格
-- **核心功能**:
- - 每个网格可设置独立的交易方向(多头/空头)
- - 根据当前价格自动匹配对应的网格
- - 支持跨网格的仓位迁移和止损
-
-### 4.2 多账号管理
-
-- **实现方式**:每个账号对应一个 `OkxQuantWebSocketClient` 实例
-- **核心功能**:
- - 支持多个交易所账号独立操作
- - 每个账号可设置独立的交易参数
- - 账号间数据隔离,互不影响
-
-### 4.3 长/空头策略支持
-
-- **实现方式**:通过 `PositionsWs` 的双层 Map 结构
-- **核心功能**:
- - 支持多头和空头方向的独立持仓管理
- - 每个方向有独立的交易逻辑
- - 支持方向切换时的仓位调整
-
-### 4.4 自动重连和心跳机制
-
-- **实现方式**:在 WebSocket 客户端中实现
-- **核心功能**:
- - 定时发送心跳包维持连接
- - 连接断开时自动重连(指数退避策略)
- - 异常处理和资源清理
-
-## 5. 配置与扩展
-
-### 5.1 网格参数配置
-
-- **当前实现**:通过 `WangGeListEnum` 硬编码配置
-- **扩展建议**:
- - 将网格参数改为可配置项(数据库或配置文件)
- - 支持动态调整网格参数
- - 提供网格参数管理界面
-
-### 5.2 交易参数配置
-
-- **核心参数**:
- - 网格间距
- - 交易方向(多头/空头)
- - 止损点
- - 交易数量
-- **扩展建议**:
- - 支持每个账号独立配置交易参数
- - 提供参数优化建议
- - 支持回测功能
-
-## 6. 总结
-
-`okxNewPrice` 包是一个完整的 OKX 量化交易系统,具有以下特点:
-
-1. **模块化设计**:清晰的分层结构,便于维护和扩展
-2. **多账号支持**:每个账号独立运行,互不影响
-3. **多网格策略**:根据价格自动切换网格,支持多头和空头策略
-4. **实时响应**:基于 WebSocket 的实时数据推送和交易执行
-5. **高可靠性**:支持心跳检测、自动重连和异常处理
-
-该系统实现了从价格获取、策略决策到订单执行的完整流程,为量化交易提供了稳定可靠的基础架构。
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/celue/CaoZuoService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/celue/CaoZuoService.java
deleted file mode 100644
index 645c35d..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/celue/CaoZuoService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.celue;
-
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-
-/**
- * @author Administrator
- */
-public interface CaoZuoService {
-
- TradeRequestParam caoZuoStrategy(String accountName, String markPx, String posSide);
-
- TradeRequestParam caoZuoHandler(String accountName, String markPx, String posSide);
-
- /**
- * 止损 事件
- * @param accountName
- * @param markPx
- * @param posSide
- * @return
- */
- TradeRequestParam caoZuoZhiSunEvent(String accountName, String markPx, String posSide);
-
- /**
- * 初始化 事件
- * @param accountName
- * @param markPx
- * @param posSide
- * @return
- */
- TradeRequestParam caoZuoInitEvent(String accountName, String markPx, String posSide);
-
- TradeRequestParam chooseEvent(TradeRequestParam tradeRequestParam);
-
- TradeRequestParam caoZuoLong(TradeRequestParam tradeRequestParam);
-
- TradeRequestParam caoZuoShort(TradeRequestParam tradeRequestParam);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/celue/CaoZuoServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/celue/CaoZuoServiceImpl.java
deleted file mode 100644
index 9d6a2e2..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/celue/CaoZuoServiceImpl.java
+++ /dev/null
@@ -1,613 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.celue;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.xcong.excoin.modules.okxNewPrice.indicator.strategy.CoreTechnicalStrategy;
-import com.xcong.excoin.modules.okxNewPrice.indicator.strategy.TechnicalIndicatorStrategy;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.*;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListQueue;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListService;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import com.xcong.excoin.rabbit.pricequeue.AscBigDecimal;
-import com.xcong.excoin.rabbit.pricequeue.DescBigDecimal;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.Map;
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 操作服务实现类,用于处理与交易相关的逻辑操作。
- * 包括根据市场行情判断是否进行加仓或减仓,并维护相关价格队列。
- *
- * @author Administrator
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class CaoZuoServiceImpl implements CaoZuoService {
-
- private final WangGeListService wangGeListService;
- private final RedisUtils redisUtils;
-
- @Override
- public TradeRequestParam caoZuoStrategy(String accountName, String markPx, String posSide) {
- TradeRequestParam tradeRequestParam = new TradeRequestParam();
- tradeRequestParam.setAccountName(accountName);
- tradeRequestParam.setMarkPx(markPx);
- tradeRequestParam.setInstId(CoinEnums.HE_YUE.getCode());
- tradeRequestParam.setTdMode(CoinEnums.CROSS.getCode());
- tradeRequestParam.setPosSide(posSide);
- tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode());
-
- log.info("操作账户:{},当前价格: {},仓位方向: {}", accountName,markPx,posSide);
- /**
- * 准备工作
- * 1、准备好下单的基本信息
- */
- // 系统设置的开关,等于冷静中,则代表不开仓
- String outStr = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.OUT.name());
- if (OrderParamEnums.OUT_YES.getValue().equals(outStr)){
- log.error("冷静中,不允许下单......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return tradeRequestParam;
- }
- BigDecimal cashBal = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get("cashBal"));
- /**
- * 判断止损抗压
- */
- BigDecimal realKuiSunAmount = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get("upl"));
- log.info("实际盈亏金额: {}", realKuiSunAmount);
- String zhiSunPercent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.ZHI_SUN.name());
- BigDecimal zhiSunAmount = cashBal.multiply(new BigDecimal(zhiSunPercent));
- log.info("预期亏损金额: {}", zhiSunAmount);
- String kangYaPercent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.KANG_CANG.name());
- BigDecimal kangYaAmount = cashBal.multiply(new BigDecimal(kangYaPercent));
- log.info("预期抗仓金额: {}", kangYaAmount);
-
- if (realKuiSunAmount.compareTo(BigDecimal.ZERO) < 0){
- realKuiSunAmount = realKuiSunAmount.multiply(new BigDecimal("-1"));
- // 账户预期亏损金额比这个还小时,立即止损
- if (realKuiSunAmount.compareTo(zhiSunAmount) > 0){
- log.error("账户冷静止损......");
- WsMapBuild.saveStringToMap(InstrumentsWs.getAccountMap(accountName), CoinEnums.OUT.name(), OrderParamEnums.OUT_YES.getValue());
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- return caoZuoZhiSunEvent(accountName, markPx, posSide);
- }
- // 判断抗压
- if (realKuiSunAmount.compareTo(kangYaAmount) > 0 && realKuiSunAmount.compareTo(zhiSunAmount) <= 0){
- log.error("账户紧张扛仓......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return tradeRequestParam;
- }
- }
-
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- // 判断是否保证金超标
- if (PositionsWs.getAccountMap(positionAccountName).get("imr") == null){
- log.error("没有获取到持仓信息,等待初始化......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return tradeRequestParam;
- }
- BigDecimal ordFrozImr = PositionsWs.getAccountMap(positionAccountName).get("imr");
- BigDecimal totalOrderUsdt = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get(CoinEnums.TOTAL_ORDER_USDT.name()))
- .divide(new BigDecimal("2"), RoundingMode.DOWN);
- if (ordFrozImr.compareTo(totalOrderUsdt) >= 0){
- log.error("已满仓......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return tradeRequestParam;
- }
-
- if (PositionsWs.getAccountMap(positionAccountName).get("pos") == null){
- log.error("没有获取到持仓信息,等待初始化......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return tradeRequestParam;
- }
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- return tradeRequestParam;
- }
-
- /**
- * 执行主要的操作逻辑,包括读取合约状态、获取市场价格信息,
- * 并根据当前持仓均价和标记价格决定是否执行买卖操作。
- *
- * @return 返回操作类型字符串(如买入BUY、卖出SELL等),如果无有效操作则返回null
- */
- @Override
- public TradeRequestParam caoZuoHandler(String accountName, String markPx, String posSide) {
- TradeRequestParam tradeRequestParam = new TradeRequestParam();
- tradeRequestParam.setAccountName(accountName);
- tradeRequestParam.setMarkPx(markPx);
- tradeRequestParam.setInstId(CoinEnums.HE_YUE.getCode());
- tradeRequestParam.setTdMode(CoinEnums.CROSS.getCode());
- tradeRequestParam.setPosSide(posSide);
- tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode());
-
- log.info("操作账户:{},当前价格: {},仓位方向: {}", accountName,markPx,posSide);
- /**
- * 准备工作
- * 1、准备好下单的基本信息
- */
- // 系统设置的开关,等于冷静中,则代表不开仓
- String outStr = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.OUT.name());
- if (OrderParamEnums.OUT_YES.getValue().equals(outStr)){
- log.error("冷静中,不允许下单......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return chooseEvent(tradeRequestParam);
- }
- BigDecimal cashBal = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get("cashBal"));
- /**
- * 判断止损抗压
- */
- BigDecimal realKuiSunAmount = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get("upl"));
- log.info("实际盈亏金额: {}", realKuiSunAmount);
- String zhiSunPercent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.ZHI_SUN.name());
- BigDecimal zhiSunAmount = cashBal.multiply(new BigDecimal(zhiSunPercent));
- log.info("预期亏损金额: {}", zhiSunAmount);
- String kangYaPercent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.KANG_CANG.name());
- BigDecimal kangYaAmount = cashBal.multiply(new BigDecimal(kangYaPercent));
- log.info("预期抗仓金额: {}", kangYaAmount);
-
- if (realKuiSunAmount.compareTo(BigDecimal.ZERO) < 0){
- realKuiSunAmount = realKuiSunAmount.multiply(new BigDecimal("-1"));
- // 账户预期亏损金额比这个还小时,立即止损
- if (realKuiSunAmount.compareTo(zhiSunAmount) > 0){
- log.error("账户冷静止损......");
- WsMapBuild.saveStringToMap(InstrumentsWs.getAccountMap(accountName), CoinEnums.OUT.name(), OrderParamEnums.OUT_YES.getValue());
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- return caoZuoZhiSunEvent(accountName, markPx, posSide);
- }
- // 判断抗压
- if (realKuiSunAmount.compareTo(kangYaAmount) > 0 && realKuiSunAmount.compareTo(zhiSunAmount) <= 0){
- log.error("账户紧张扛仓......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return chooseEvent(tradeRequestParam);
- }
- }
-
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- // 判断是否保证金超标
- if (PositionsWs.getAccountMap(positionAccountName).get("imr") == null){
- log.error("没有获取到持仓信息,等待初始化......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return chooseEvent(tradeRequestParam);
- }
- BigDecimal ordFrozImr = PositionsWs.getAccountMap(positionAccountName).get("imr");
- BigDecimal totalOrderUsdt = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get(CoinEnums.TOTAL_ORDER_USDT.name()))
- .divide(new BigDecimal("2"), RoundingMode.DOWN);
- if (ordFrozImr.compareTo(totalOrderUsdt) >= 0){
- log.error("已满仓......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return chooseEvent(tradeRequestParam);
- }
-
- if (PositionsWs.getAccountMap(positionAccountName).get("pos") == null){
- log.error("没有获取到持仓信息,等待初始化......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return chooseEvent(tradeRequestParam);
- }
- BigDecimal pos = PositionsWs.getAccountMap(positionAccountName).get("pos");
- if (BigDecimal.ZERO.compareTo( pos) >= 0) {
- log.error("持仓数量为零,进行初始化订单");
- return caoZuoInitEvent(accountName, markPx, posSide);
- }
-
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- return chooseEvent(tradeRequestParam);
- }
-
- @Override
- public TradeRequestParam caoZuoZhiSunEvent(String accountName, String markPx, String posSide) {
-
- log.info("历史网格:操作账户:{},当前价格: {},仓位方向: {}", accountName,markPx,posSide);
- /**
- * 初始化订单请求参数
- * 获取仓位数量
- * 获取仓位方向
- */
- TradeRequestParam tradeRequestParam = new TradeRequestParam();
- tradeRequestParam.setAccountName(accountName);
- tradeRequestParam.setMarkPx(markPx);
- tradeRequestParam.setInstId(CoinEnums.HE_YUE.getCode());
- tradeRequestParam.setTdMode(CoinEnums.CROSS.getCode());
- tradeRequestParam.setPosSide(posSide);
- tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode());
-
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- String side = null;
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)){
- side = CoinEnums.SIDE_SELL.getCode();
- }
- if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)){
- side = CoinEnums.SIDE_BUY.getCode();
- }
- tradeRequestParam.setSide(side);
-
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
-
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- BigDecimal pos = PositionsWs.getAccountMap(positionAccountName).get("pos");
- if (BigDecimal.ZERO.compareTo( pos) >= 0) {
- log.error("历史网格止损方向没有持仓");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- }
- tradeRequestParam.setSz(String.valueOf( pos));
- return tradeRequestParam;
-
- }
-
- @Override
- public TradeRequestParam caoZuoInitEvent(String accountName, String markPx, String posSide) {
-
- log.info("当前网格初始化:操作账户:{},当前价格: {},仓位方向: {}", accountName,markPx,posSide);
- /**
- * 初始化订单请求参数
- * 获取仓位数量
- * 获取仓位方向
- */
- TradeRequestParam tradeRequestParam = new TradeRequestParam();
- tradeRequestParam.setAccountName(accountName);
- tradeRequestParam.setMarkPx(markPx);
- tradeRequestParam.setInstId(CoinEnums.HE_YUE.getCode());
- tradeRequestParam.setTdMode(CoinEnums.CROSS.getCode());
- tradeRequestParam.setPosSide(posSide);
- tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode());
-
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- String side = null;
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)){
- side = CoinEnums.SIDE_BUY.getCode();
- }
- if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)){
- side = CoinEnums.SIDE_SELL.getCode();
- }
- tradeRequestParam.setSide(side);
-
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
- String sz = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.BUY_CNT_INIT.name());
- tradeRequestParam.setSz(sz);
-
- WsMapBuild.saveStringToMap(OrderInfoWs.getAccountMap(accountName), "orderPrice", String.valueOf(markPx));
- return tradeRequestParam;
- }
-
- @Override
- public TradeRequestParam chooseEvent(TradeRequestParam tradeRequestParam) {
- log.info("开始执行chooseEvent......");
- if (OrderParamEnums.TRADE_NO.getValue().equals(tradeRequestParam.getTradeType())){
- return tradeRequestParam;
- }
- if (OrderParamEnums.TRADE_YES.getValue().equals(tradeRequestParam.getTradeType())){
- String posSide = tradeRequestParam.getPosSide();
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)){
- tradeRequestParam = caoZuoLong(tradeRequestParam);
- }else if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)){
- tradeRequestParam = caoZuoShort(tradeRequestParam);
- }
- }
- return tradeRequestParam;
- }
-
- @Override
- public TradeRequestParam caoZuoLong(TradeRequestParam tradeRequestParam) {
- log.info("开始做{}执行操作CaoZuoServiceImpl......",tradeRequestParam.getPosSide());
-
- String accountName = tradeRequestParam.getAccountName();
- String markPxStr = tradeRequestParam.getMarkPx();
- String posSide = tradeRequestParam.getPosSide();
-
- try {
-
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- // 获取标记价格和平均持仓价格
- BigDecimal markPx = new BigDecimal(markPxStr);
- BigDecimal avgPx = PositionsWs.getAccountMap(positionAccountName).get("avgPx");
- log.info("持仓价格: {}, 当前价格:{},匹配队列中......", avgPx, markPx);
- // 初始化网格队列
- PriorityBlockingQueue<AscBigDecimal> queueAsc = WangGeListQueue.getQueueAsc();
- PriorityBlockingQueue<DescBigDecimal> queueKaiCang = wangGeListService.initKaiCang(avgPx, queueAsc);
- PriorityBlockingQueue<AscBigDecimal> queuePingCang = wangGeListService.initPingCang(avgPx, queueAsc);
-
- // 处理订单价格在队列中的情况
- String orderPrice = OrderInfoWs.getAccountMap(accountName).get("orderPrice");
- log.info("上一次网格触发价格: {}", orderPrice);
- handleOrderPriceInQueues(orderPrice, queueKaiCang, queuePingCang);
- // 判断是加仓还是减仓
- if (avgPx.compareTo(markPx) > 0) {
- log.info("开始买入开多...");
- if (!queueKaiCang.isEmpty()) {
- DescBigDecimal kaiCang = queueKaiCang.peek();
- log.info("买入开多队列价格{}", kaiCang.getValue());
- if (kaiCang != null && markPx.compareTo(kaiCang.getValue()) <= 0 && avgPx.compareTo(kaiCang.getValue()) >= 0) {
- log.info("开始买入开多...买入开多队列价格价格大于当前价格{}>{}", kaiCang.getValue(), markPx);
- WsMapBuild.saveStringToMap(OrderInfoWs.getAccountMap(accountName), "orderPrice", String.valueOf(markPx));
- String side = CoinEnums.SIDE_BUY.getCode();
- tradeRequestParam.setSide(side);
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
- String sz = buyCntTimeLongEvent(accountName, avgPx, markPx);
- tradeRequestParam.setSz(sz);
- log.info("买入开多参数准备成功......");
- } else {
- log.info("未触发加仓......,等待");
- }
- }else{
- // 队列为空
- log.info("超出了网格设置...");
- }
- } else if (avgPx.compareTo(markPx) < 0) {
- log.info("开始卖出平多...");
- if (!queuePingCang.isEmpty()) {
- AscBigDecimal pingCang = queuePingCang.peek();
- log.info("卖出平多队列价格:{}", pingCang.getValue());
- if (pingCang != null && avgPx.compareTo(pingCang.getValue()) < 0) {
- log.info("开始卖出平多...卖出平多队列价格大于开仓价格{}>{}", pingCang.getValue(), avgPx);
- // 手续费
- BigDecimal feeValue = PositionsWs.getAccountMap(positionAccountName).get("fee").multiply(new BigDecimal(2));
- //未实现收益
- BigDecimal uplValue = PositionsWs.getAccountMap(positionAccountName).get("upl");
- //已实现收益
- BigDecimal realizedPnlValue = PositionsWs.getAccountMap(positionAccountName).get("realizedPnl");
- realizedPnlValue = realizedPnlValue.add(feeValue);
-
- //持仓保证金
- BigDecimal imr = PositionsWs.getAccountMap(positionAccountName).get("imr");
- String pingCangImr = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name());
- BigDecimal imrValue = imr.multiply(new BigDecimal(pingCangImr));
-
- if (realizedPnlValue.compareTo(BigDecimal.ZERO) <= 0) {
- BigDecimal realizedPnlValueZheng = realizedPnlValue.multiply(new BigDecimal("-1"));
- if (uplValue.compareTo(realizedPnlValue) > 0 && uplValue.compareTo(imrValue.add(realizedPnlValueZheng)) >= 0) {
- log.info("当前未实现盈亏:{}大于预计收益>{},赚钱咯", uplValue, imrValue.add(realizedPnlValueZheng));
- WsMapBuild.saveStringToMap(OrderInfoWs.getAccountMap(accountName), "orderPrice", String.valueOf(markPx));
- String side = CoinEnums.SIDE_SELL.getCode();
- tradeRequestParam.setSide(side);
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
- BigDecimal sz = PositionsWs.getAccountMap(positionAccountName).get("pos");
- tradeRequestParam.setSz(String.valueOf( sz));
- log.info("卖出平多参数准备成功......");
- }else{
- log.info("当前未实现盈亏:{}没有大于预计收益>{},钱在路上了", uplValue, imrValue.add(realizedPnlValueZheng));
- }
- }else {
- if (uplValue.compareTo(imrValue.add(feeValue)) >= 0) {
- log.info("当前未实现盈亏:{}大于预计收益>{},赚钱咯", uplValue, imrValue.add(feeValue));
- WsMapBuild.saveStringToMap(OrderInfoWs.getAccountMap(accountName), "orderPrice", String.valueOf(markPx));
- String side = CoinEnums.SIDE_SELL.getCode();
- tradeRequestParam.setSide(side);
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
- BigDecimal sz = PositionsWs.getAccountMap(positionAccountName).get("pos");
- tradeRequestParam.setSz(String.valueOf( sz));
- log.info("卖出平多参数准备成功......");
- }else{
- log.info("当前未实现盈亏:{}没有大于预计收益>{},钱在路上了", uplValue, imrValue.add(feeValue));
- }
- }
- } else {
- log.info("未触发减仓......,等待");
- }
- }else{
- // 队列为空
- log.info("超出了网格设置...");
- }
- } else {
- log.info("价格波动较小......,等待");
- }
- return tradeRequestParam;
- } catch (NumberFormatException e) {
- log.error("开多方向异常", e);
- return tradeRequestParam;
- }
- }
-
- @Override
- public TradeRequestParam caoZuoShort(TradeRequestParam tradeRequestParam) {
- log.info("开始做{}执行操作CaoZuoServiceImpl......",tradeRequestParam.getPosSide());
-
- String accountName = tradeRequestParam.getAccountName();
- String markPxStr = tradeRequestParam.getMarkPx();
- String posSide = tradeRequestParam.getPosSide();
-
- try {
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- // 获取标记价格和平均持仓价格
- BigDecimal markPx = new BigDecimal(markPxStr);
- BigDecimal avgPx = PositionsWs.getAccountMap(positionAccountName).get("avgPx");
- log.info("持仓价格: {}, 当前价格:{},匹配队列中......", avgPx, markPx);
-
- // 初始化网格队列
- PriorityBlockingQueue<AscBigDecimal> queueAsc = WangGeListQueue.getQueueAsc();
- PriorityBlockingQueue<DescBigDecimal> queueKaiCang = wangGeListService.initKaiCang(avgPx, queueAsc);
- PriorityBlockingQueue<AscBigDecimal> queuePingCang = wangGeListService.initPingCang(avgPx, queueAsc);
-
- // 处理订单价格在队列中的情况
- String orderPrice = OrderInfoWs.getAccountMap(accountName).get("orderPrice");
- log.info("上一次网格触发价格:{}", orderPrice);
- handleOrderPriceInQueues(orderPrice, queueKaiCang, queuePingCang);
- // 判断是加仓还是减仓
- if (avgPx.compareTo(markPx) > 0) {
- log.info("开始买入平空...");
- if (!queueKaiCang.isEmpty()) {
- DescBigDecimal kaiCang = queueKaiCang.peek();
- log.info("买入平空队列价格{}", kaiCang.getValue());
- if (kaiCang != null && avgPx.compareTo(kaiCang.getValue()) >= 0) {
- log.info("开始买入平空...买入平空队列价格小于开仓价格{}<{}", kaiCang.getValue(), avgPx);
-
- // 手续费
- BigDecimal feeValue = PositionsWs.getAccountMap(positionAccountName).get("fee").multiply(new BigDecimal("2"));
- //未实现收益
- BigDecimal uplValue = PositionsWs.getAccountMap(positionAccountName).get("upl");
- //已实现收益
- BigDecimal realizedPnlValue = PositionsWs.getAccountMap(positionAccountName).get("realizedPnl");
- realizedPnlValue = realizedPnlValue.add(feeValue);
-
- //持仓保证金
- BigDecimal imr = PositionsWs.getAccountMap(positionAccountName).get("imr");
- String pingCangImr = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name());
- BigDecimal imrValue = imr.multiply(new BigDecimal(pingCangImr));
-
- if (realizedPnlValue.compareTo(BigDecimal.ZERO) <= 0) {
- BigDecimal realizedPnlValueZheng = realizedPnlValue.multiply(new BigDecimal("-1"));
- if (uplValue.compareTo(realizedPnlValue) > 0 && uplValue.compareTo(imrValue.add(realizedPnlValueZheng)) >= 0) {
- log.info("当前未实现盈亏:{}大于预计收益>{},赚钱咯", uplValue, imrValue.add(realizedPnlValueZheng));
- WsMapBuild.saveStringToMap(OrderInfoWs.getAccountMap(accountName), "orderPrice", String.valueOf(markPx));
- String side = CoinEnums.SIDE_BUY.getCode();
- tradeRequestParam.setSide(side);
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
- BigDecimal sz = PositionsWs.getAccountMap(positionAccountName).get("pos");
- tradeRequestParam.setSz(String.valueOf( sz));
- log.info("买入平空参数准备成功......");
- }else{
- log.info("当前未实现盈亏:{}没有大于预计收益>{},钱在路上了", uplValue, imrValue.add(realizedPnlValueZheng));
- }
- }else {
- if (uplValue.compareTo(imrValue.add(feeValue)) >= 0) {
- WsMapBuild.saveStringToMap(OrderInfoWs.getAccountMap(accountName), "orderPrice", String.valueOf(markPx));
- log.info("当前未实现盈亏:{}大于预计收益>{},赚钱咯", uplValue, imrValue.add(feeValue));
- String side = CoinEnums.SIDE_BUY.getCode();
- tradeRequestParam.setSide(side);
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
- BigDecimal sz = PositionsWs.getAccountMap(positionAccountName).get("pos");
- tradeRequestParam.setSz(String.valueOf( sz));
- log.info("买入平空参数准备成功......");
- }else{
- log.info("当前未实现盈亏:{}没有大于预计收益>{},钱在路上了", uplValue, imrValue.add(feeValue));
- }
- }
- } else {
- log.info("未触发减仓......,等待");
- }
- }else{
- log.info("开始减仓,但是超出了网格设置...");
- }
- } else if (avgPx.compareTo(markPx) < 0) {
- log.info("开始卖出开空...");
- if (!queuePingCang.isEmpty()) {
- AscBigDecimal pingCang = queuePingCang.peek();
- log.info("上限队列价格: {}", pingCang.getValue());
- if (pingCang != null && markPx.compareTo(pingCang.getValue()) >= 0 && avgPx.compareTo(pingCang.getValue()) < 0) {
- log.info("开始加仓...上限队列价格小于当前价格{}<={}", pingCang.getValue(), markPx);
- WsMapBuild.saveStringToMap(OrderInfoWs.getAccountMap(accountName), "orderPrice", String.valueOf(markPx));
- String side = CoinEnums.SIDE_SELL.getCode();
- tradeRequestParam.setSide(side);
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
- String sz = buyCntTimeShortEvent(accountName, avgPx, markPx);
- tradeRequestParam.setSz(sz);
- log.info("卖出开空参数准备成功......");
- } else {
- log.info("未触发加仓......,等待");
- }
- }else{
- // 队列为空
- log.info("超出了网格设置...");
- }
- } else {
- log.info("价格波动较小......,等待");
- }
- return tradeRequestParam;
- } catch (NumberFormatException e) {
- log.error("开空方向异常", e);
- return tradeRequestParam;
- }
- }
-
- private String buyCntTimeLongEvent(String accountName, BigDecimal avgPx, BigDecimal markPx){
- //判断当前价格和开仓价格直接间隔除以间距,取整,获取的数量是否大于等于0,如果大于0,则下单基础张数*倍数
- String buyCntTime = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.BUY_CNT_TIME.name());
- log.info("倍数次数间隔{}", buyCntTime);
- BigDecimal subtract = avgPx.subtract(markPx);
- log.info("倍数价格差距{}", subtract);
- BigDecimal divide = subtract.divide(new BigDecimal(buyCntTime), 0, RoundingMode.DOWN).add(BigDecimal.ONE);
- log.info("倍数次数{}", divide);
- String buyCntInit = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.BUY_CNT_INIT.name());
- return String.valueOf(divide.multiply(new BigDecimal(buyCntInit)));
- }
-
- private String buyCntTimeShortEvent(String accountName, BigDecimal avgPx, BigDecimal markPx){
- //判断当前价格和开仓价格直接间隔除以间距,取整,获取的数量是否大于等于0,如果大于0,则下单基础张数*倍数
-
- String buyCntTime = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.BUY_CNT_TIME.name());
- log.info("倍数次数间隔{}", buyCntTime);
- BigDecimal subtract = markPx.subtract(avgPx);
- log.info("倍数价格差距{}", subtract);
- BigDecimal divide = subtract.divide(new BigDecimal(buyCntTime), 0, RoundingMode.DOWN).add(BigDecimal.ONE);
- log.info("倍数次数{}", divide);
- String buyCntInit = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.BUY_CNT_INIT.name());
- return String.valueOf(divide.multiply(new BigDecimal(buyCntInit)));
- }
-
- /**
- * 根据订单价格更新开仓和平仓队列的内容。
- * 若该价格不在对应队列中则加入;若已存在,则从队列中移除。
- *
- * @param orderPrice 订单价格
- * @param queueKaiCang 开仓价格优先队列(降序)
- * @param queuePingCang 平仓价格优先队列(升序)
- */
- private void handleOrderPriceInQueues(String orderPrice,
- PriorityBlockingQueue<DescBigDecimal> queueKaiCang,
- PriorityBlockingQueue<AscBigDecimal> queuePingCang) {
- if (orderPrice == null) {
- return;
- }
- log.info("需要移除的价格: {}", orderPrice);
-
- BigDecimal priceDecimal;
- try {
- priceDecimal = new BigDecimal(orderPrice);
- } catch (NumberFormatException ex) {
- log.warn("无效的价格格式: {}", orderPrice);
- return;
- }
-
- // 删除比该价格大的数据
- queueKaiCang.removeIf(item -> item.getValue().compareTo(priceDecimal) >= 0);
-
- // 打印开仓队列
- StringBuilder kaiCangStr = new StringBuilder();
- kaiCangStr.append("下限队列: [");
- boolean first = true;
- for (DescBigDecimal item : queueKaiCang) {
- if (!first) {
- kaiCangStr.append(", ");
- }
- kaiCangStr.append(item.getValue());
- first = false;
- }
- kaiCangStr.append("]");
- log.info(kaiCangStr.toString());
-
- // 删除比该价格小的数据
- queuePingCang.removeIf(item -> item.getValue().compareTo(priceDecimal) <= 0);
-
- // 打印平仓队列
- StringBuilder pingCangStr = new StringBuilder();
- pingCangStr.append("上限队列: [");
- first = true;
- for (AscBigDecimal item : queuePingCang) {
- if (!first) {
- pingCangStr.append(", ");
- }
- pingCangStr.append(item.getValue());
- first = false;
- }
- pingCangStr.append("]");
- log.info(pingCangStr.toString());
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java
new file mode 100644
index 0000000..5410920
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java
@@ -0,0 +1,89 @@
+package com.xcong.excoin.modules.okxNewPrice.gridWs;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.modules.okxNewPrice.OkxGridTradeService;
+import lombok.extern.slf4j.Slf4j;
+import org.java_websocket.client.WebSocketClient;
+
+/**
+ * OKX 策略委托(算法单)频道处理器 (orders-algo)。
+ * 接收条件单状态变更推送并回调 OkxGridTradeService.onOrderUpdate()。
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class OkxAlgoOrdersChannelHandler implements OkxGridChannelHandler {
+
+ private static final String CHANNEL_NAME = "orders-algo";
+
+ private final String instId;
+ private final OkxGridTradeService gridTradeService;
+
+ public OkxAlgoOrdersChannelHandler(String instId, OkxGridTradeService gridTradeService) {
+ this.instId = instId;
+ this.gridTradeService = gridTradeService;
+ }
+
+ @Override
+ public String getChannelName() { return CHANNEL_NAME; }
+
+ @Override
+ public void subscribe(WebSocketClient ws) {
+ JSONObject msg = new JSONObject();
+ JSONObject arg = new JSONObject();
+ arg.put("channel", CHANNEL_NAME);
+ arg.put("instType", "SWAP");
+ msg.put("op", "subscribe");
+ JSONArray args = new JSONArray();
+ args.add(arg);
+ msg.put("args", args);
+ ws.send(msg.toJSONString());
+ log.info("[OKX-WS] {} 订阅成功", CHANNEL_NAME);
+ }
+
+ @Override
+ public void unsubscribe(WebSocketClient ws) {
+ JSONObject msg = new JSONObject();
+ JSONObject arg = new JSONObject();
+ arg.put("channel", CHANNEL_NAME);
+ arg.put("instType", "SWAP");
+ msg.put("op", "unsubscribe");
+ JSONArray args = new JSONArray();
+ args.add(arg);
+ msg.put("args", args);
+ ws.send(msg.toJSONString());
+ log.info("[OKX-WS] {} 取消订阅成功", CHANNEL_NAME);
+ }
+
+ @Override
+ public boolean handleMessage(JSONObject response) {
+ JSONObject arg = response.getJSONObject("arg");
+ if (arg == null || !CHANNEL_NAME.equals(arg.getString("channel"))) {
+ return false;
+ }
+ try {
+ JSONArray data = response.getJSONArray("data");
+ if (data == null || data.isEmpty()) return true;
+ for (int i = 0; i < data.size(); i++) {
+ JSONObject order = data.getJSONObject(i);
+ if (!instId.equals(order.getString("instId"))) continue;
+
+ String algoId = order.getString("algoId");
+ String state = order.getString("state");
+ String ordType = order.getString("ordType");
+ log.info("[OKX-WS] 算法单更新, algoId:{}, state:{}, ordType:{}, triggerPx:{}, actualPx:{}",
+ algoId, state, ordType,
+ order.getString("triggerPx"),
+ order.getString("actualPx"));
+
+ if (gridTradeService != null) {
+ gridTradeService.onOrderUpdate(algoId, state, ordType);
+ }
+ }
+ } catch (Exception e) {
+ log.error("[OKX-WS] {} 处理数据失败", CHANNEL_NAME, e);
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxGridChannelHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxGridChannelHandler.java
new file mode 100644
index 0000000..b0d065f
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxGridChannelHandler.java
@@ -0,0 +1,30 @@
+package com.xcong.excoin.modules.okxNewPrice.gridWs;
+
+import com.alibaba.fastjson.JSONObject;
+import org.java_websocket.client.WebSocketClient;
+
+/**
+ * OKX 网格交易 WebSocket 频道处理器接口。
+ * 对齐 Gate 版本的 GateChannelHandler。
+ *
+ * @author Administrator
+ */
+public interface OkxGridChannelHandler {
+
+ /** 频道名称,如 "candle1m"、"positions" */
+ String getChannelName();
+
+ /** 发送订阅请求 */
+ void subscribe(WebSocketClient ws);
+
+ /** 发送取消订阅请求 */
+ void unsubscribe(WebSocketClient ws);
+
+ /**
+ * 处理频道推送消息。
+ *
+ * @param response WebSocket 推送的完整 JSON
+ * @return true 表示已处理(循环停止),false 表示频道不匹配
+ */
+ boolean handleMessage(JSONObject response);
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxKlineChannelHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxKlineChannelHandler.java
new file mode 100644
index 0000000..401d236
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxKlineChannelHandler.java
@@ -0,0 +1,83 @@
+package com.xcong.excoin.modules.okxNewPrice.gridWs;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.modules.okxNewPrice.OkxGridTradeService;
+import lombok.extern.slf4j.Slf4j;
+import org.java_websocket.client.WebSocketClient;
+
+import java.math.BigDecimal;
+
+/**
+ * OKX K线频道处理器 (candle1m)。
+ * 策略的唯一价格时间驱动源,每收到一根K线触发 onKline()。
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class OkxKlineChannelHandler implements OkxGridChannelHandler {
+
+ private static final String CHANNEL_NAME = "candle1m";
+ private static final String INTERVAL = "1m";
+
+ private final String instId;
+ private final OkxGridTradeService gridTradeService;
+
+ public OkxKlineChannelHandler(String instId, OkxGridTradeService gridTradeService) {
+ this.instId = instId;
+ this.gridTradeService = gridTradeService;
+ }
+
+ @Override
+ public String getChannelName() { return CHANNEL_NAME; }
+
+ @Override
+ public void subscribe(WebSocketClient ws) {
+ JSONObject msg = new JSONObject();
+ JSONObject arg = new JSONObject();
+ arg.put("channel", CHANNEL_NAME);
+ arg.put("instId", instId);
+ msg.put("op", "subscribe");
+ JSONArray args = new JSONArray();
+ args.add(arg);
+ msg.put("args", args);
+ ws.send(msg.toJSONString());
+ log.info("[OKX-WS] {} 订阅成功, instId:{}", CHANNEL_NAME, instId);
+ }
+
+ @Override
+ public void unsubscribe(WebSocketClient ws) {
+ JSONObject msg = new JSONObject();
+ JSONObject arg = new JSONObject();
+ arg.put("channel", CHANNEL_NAME);
+ arg.put("instId", instId);
+ msg.put("op", "unsubscribe");
+ JSONArray args = new JSONArray();
+ args.add(arg);
+ msg.put("args", args);
+ ws.send(msg.toJSONString());
+ log.info("[OKX-WS] {} 取消订阅成功", CHANNEL_NAME);
+ }
+
+ @Override
+ public boolean handleMessage(JSONObject response) {
+ JSONObject arg = response.getJSONObject("arg");
+ if (arg == null || !CHANNEL_NAME.equals(arg.getString("channel"))) {
+ return false;
+ }
+ try {
+ JSONArray data = response.getJSONArray("data");
+ if (data == null || data.isEmpty()) return true;
+ // OKX K线数据格式: [ts, o, h, l, c, vol, volCcy, volCcyQuote, confirm]
+ JSONArray candle = data.getJSONArray(0);
+ if (candle == null || candle.size() < 5) return true;
+ BigDecimal closePx = candle.getBigDecimal(4); // 收盘价在索引4
+ if (closePx != null && gridTradeService != null) {
+ gridTradeService.onKline(closePx);
+ }
+ } catch (Exception e) {
+ log.error("[OKX-WS] {} 处理数据失败", CHANNEL_NAME, e);
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java
new file mode 100644
index 0000000..5749544
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java
@@ -0,0 +1,89 @@
+package com.xcong.excoin.modules.okxNewPrice.gridWs;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.modules.okxNewPrice.OkxGridTradeService;
+import lombok.extern.slf4j.Slf4j;
+import org.java_websocket.client.WebSocketClient;
+
+import java.math.BigDecimal;
+
+/**
+ * OKX 持仓频道处理器 (positions)。
+ * 接收持仓更新推送并回调 OkxGridTradeService.onPositionUpdate()。
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class OkxPositionsChannelHandler implements OkxGridChannelHandler {
+
+ private static final String CHANNEL_NAME = "positions";
+
+ private final String instId;
+ private final OkxGridTradeService gridTradeService;
+
+ public OkxPositionsChannelHandler(String instId, OkxGridTradeService gridTradeService) {
+ this.instId = instId;
+ this.gridTradeService = gridTradeService;
+ }
+
+ @Override
+ public String getChannelName() { return CHANNEL_NAME; }
+
+ @Override
+ public void subscribe(WebSocketClient ws) {
+ JSONObject msg = new JSONObject();
+ JSONObject arg = new JSONObject();
+ arg.put("channel", CHANNEL_NAME);
+ arg.put("instType", "SWAP");
+ msg.put("op", "subscribe");
+ JSONArray args = new JSONArray();
+ args.add(arg);
+ msg.put("args", args);
+ ws.send(msg.toJSONString());
+ log.info("[OKX-WS] {} 订阅成功", CHANNEL_NAME);
+ }
+
+ @Override
+ public void unsubscribe(WebSocketClient ws) {
+ JSONObject msg = new JSONObject();
+ JSONObject arg = new JSONObject();
+ arg.put("channel", CHANNEL_NAME);
+ arg.put("instType", "SWAP");
+ msg.put("op", "unsubscribe");
+ JSONArray args = new JSONArray();
+ args.add(arg);
+ msg.put("args", args);
+ ws.send(msg.toJSONString());
+ log.info("[OKX-WS] {} 取消订阅成功", CHANNEL_NAME);
+ }
+
+ @Override
+ public boolean handleMessage(JSONObject response) {
+ JSONObject arg = response.getJSONObject("arg");
+ if (arg == null || !CHANNEL_NAME.equals(arg.getString("channel"))) {
+ return false;
+ }
+ try {
+ JSONArray data = response.getJSONArray("data");
+ if (data == null || data.isEmpty()) return true;
+ for (int i = 0; i < data.size(); i++) {
+ JSONObject pos = data.getJSONObject(i);
+ if (!instId.equals(pos.getString("instId"))) continue;
+
+ String posSide = pos.getString("posSide");
+ BigDecimal posSize = new BigDecimal(pos.getString("pos"));
+ BigDecimal avgPx = new BigDecimal(pos.getString("avgPx"));
+ log.info("[OKX-WS] 持仓更新, instId:{}, posSide:{}, pos:{}, avgPx:{}",
+ instId, posSide, posSize, avgPx);
+
+ if (gridTradeService != null) {
+ gridTradeService.onPositionUpdate(instId, posSide, posSize, avgPx);
+ }
+ }
+ } catch (Exception e) {
+ log.error("[OKX-WS] {} 处理数据失败", CHANNEL_NAME, e);
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/AdvancedMA.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/AdvancedMA.java
deleted file mode 100644
index 4308fcb..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/AdvancedMA.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.List;
-
-/**
- * Advanced MA (Moving Average) 指标实现
- * 支持扩展周期的指数移动平均线(EMA),用于三重EMA交叉系统
- *
- * 作用:
- * 1. 基于三重EMA交叉系统识别趋势方向和强度
- * 2. 当9EMA > 21EMA > 55EMA时形成多头排列,提示上涨趋势
- * 3. 当9EMA < 21EMA < 55EMA时形成空头排列,提示下跌趋势
- * 4. 计算三线粘合度,自动过滤震荡行情
- *
- * 价格参数类型:
- * - 参数名称:prices
- * - 参数类型:List<BigDecimal>
- * - 参数说明:需要至少1个价格数据点用于计算,根据不同周期需求更多数据点
- *
- * 推荐时间粒度及优缺点:
- * 1. 5分钟(5m):
- * - 优点:适合短线三重EMA交叉策略
- * - 缺点:需要频繁监控,容易受短期波动影响
- * 2. 15分钟(15m):
- * - 优点:平衡了信号可靠性和反应速度
- * - 缺点:仍有一定噪音
- * 3. 1小时(1h):
- * - 优点:信号较为可靠,适合中期趋势跟踪
- * - 缺点:反应较慢
- * 4. 4小时(4h)及以上:
- * - 优点:趋势信号明确,适合长期持仓
- * - 缺点:反应滞后,入场点较晚
- */
-@Slf4j
-@Getter
-@Setter
-public class AdvancedMA extends IndicatorBase {
-
- // 扩展周期 - 三重EMA交叉系统
- public static final int EMA9 = 9;
- public static final int EMA21 = 21;
- public static final int EMA55 = 55;
-
- private BigDecimal ema9 = BigDecimal.ZERO;
- private BigDecimal ema21 = BigDecimal.ZERO;
- private BigDecimal ema55 = BigDecimal.ZERO;
-
- private BigDecimal prevEma9 = null;
- private BigDecimal prevEma21 = null;
- private BigDecimal prevEma55 = null;
-
- /**
- * 计算三重EMA交叉系统的指标
- * @param prices 价格列表
- */
- public void calculateTripleEMA(List<BigDecimal> prices) {
- if (prices == null || prices.isEmpty()) {
- return;
- }
-
- // 计算三重EMA
- prevEma9 = calculateEMA(prices, EMA9, prevEma9);
- ema9 = prevEma9;
-
- prevEma21 = calculateEMA(prices, EMA21, prevEma21);
- ema21 = prevEma21;
-
- prevEma55 = calculateEMA(prices, EMA55, prevEma55);
- ema55 = prevEma55;
-
- log.info("三重EMA计算结果 - EMA9: {}, EMA21: {}, EMA55: {}",
- ema9, ema21, ema55);
- }
-
- /**
- * 判断三重EMA多头排列
- * 当9EMA > 21EMA > 55EMA时触发多头条件
- * @return 是否形成多头排列
- */
- public boolean isBullish() {
- return ema9.compareTo(ema21) > 0 && ema21.compareTo(ema55) > 0;
- }
-
- /**
- * 判断三重EMA空头排列
- * 当9EMA < 21EMA < 55EMA时触发空头条件
- * @return 是否形成空头排列
- */
- public boolean isBearish() {
- return ema9.compareTo(ema21) < 0 && ema21.compareTo(ema55) < 0;
- }
-
- /**
- * 计算三线粘合度
- * 用于自动过滤震荡行情
- * @return 粘合度百分比,值越小表示越粘合
- */
- public BigDecimal calculatePercent() {
- // 计算最大值和最小值
- BigDecimal max = ema9.max(ema21).max(ema55);
- BigDecimal min = ema9.min(ema21).min(ema55);
-
- // 计算平均价
- BigDecimal avg = ema9.add(ema21).add(ema55).divide(new BigDecimal(3), 8, RoundingMode.HALF_UP);
-
- // 计算粘合度: (最大值 - 最小值) / 平均值 * 100%
- if (avg.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- }
-
- return max.subtract(min).divide(avg, 8, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
- }
-
- /**
- * 检查是否处于震荡行情(三线粘合)
- * 当三线粘合度 < 2% 时判定为震荡行情
- * @return 是否处于震荡行情
- */
- public boolean isUpAndDown() {
- BigDecimal bigDecimal = calculatePercent();
- return bigDecimal.compareTo(new BigDecimal(2)) < 0;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/BOLL.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/BOLL.java
deleted file mode 100644
index 7075f88..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/BOLL.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.List;
-
-/**
- * BOLL (Bollinger Bands) 指标实现
- * 计算逻辑:
- * 1. 中轨(MB)= N日移动平均线
- * 2. 上轨(UP)= 中轨 + K倍标准差
- * 3. 下轨(DN)= 中轨 - K倍标准差
- *
- * 作用:
- * 1. 测量价格波动范围和市场宽度
- * 2. 价格突破上轨,提示超买或趋势加速
- * 3. 价格跌破下轨,提示超卖或趋势加速
- * 4. 轨道收窄,提示即将发生剧烈波动
- * 5. 价格回归轨道内,提示趋势可能反转
- *
- * 价格参数类型:
- * - 参数名称:prices
- * - 参数类型:List<BigDecimal>
- * - 参数说明:需要至少20个(默认周期)价格数据点用于计算
- *
- * 推荐时间粒度及优缺点:
- * 1. 1分钟(1m):
- * - 优点:反应迅速,适合超短线突破策略
- * - 缺点:布林带宽度窄,假突破多
- * 2. 5分钟(5m):
- * - 优点:布林带宽度适中,突破信号相对可靠
- * - 缺点:仍有一定假突破
- * 3. 15分钟(15m):
- * - 优点:适合日内交易,突破信号较为可靠
- * - 缺点:反应速度较慢
- * 4. 1小时(1h)及以上:
- * - 优点:布林带宽度稳定,突破信号可靠
- * - 缺点:反应滞后,不适合短线交易
- */
-@Slf4j
-@Getter
-@Setter
-public class BOLL extends IndicatorBase {
-
- private static final int DEFAULT_PERIOD = 20;
- private static final double DEFAULT_K = 2.0;
-
- private int period = DEFAULT_PERIOD;
- private BigDecimal k = new BigDecimal(DEFAULT_K);
- private BigDecimal mid = BigDecimal.ZERO;
- private BigDecimal upper = BigDecimal.ZERO;
- private BigDecimal lower = BigDecimal.ZERO;
-
- public BOLL() {}
-
- public BOLL(int period, double k) {
- this.period = period;
- this.k = new BigDecimal(k);
- }
-
- /**
- * 计算BOLL指标
- * @param prices 价格列表
- */
- public void calculate(List<BigDecimal> prices) {
- if (prices == null || prices.size() < period) {
- return;
- }
-
- // 计算中轨(MB)= N日移动平均线
- mid = calculateMA(prices, period);
-
- // 计算标准差
- BigDecimal stdDev = calculateStdDev(prices, period);
-
- // 计算上轨(UP)和下轨(DN)
- BigDecimal bandWidth = k.multiply(stdDev);
- upper = mid.add(bandWidth).setScale(8, RoundingMode.HALF_UP);
- lower = mid.subtract(bandWidth).setScale(8, RoundingMode.HALF_UP);
-
- log.info("BOLL计算结果 - 中轨: {}, 上轨: {}, 下轨: {}", mid, upper, lower);
- }
-
- /**
- * 判断价格是否突破上轨
- * @param price 当前价格
- * @return 是否突破上轨
- */
- public boolean isBreakUpper(BigDecimal price) {
- return price.compareTo(upper) > 0;
- }
-
- /**
- * 判断价格是否跌破下轨
- * @param price 当前价格
- * @return 是否跌破下轨
- */
- public boolean isBreakLower(BigDecimal price) {
- return price.compareTo(lower) < 0;
- }
-
- /**
- * 判断价格是否回归上轨下方
- * @param price 当前价格
- * @param prevPrice 前一期价格
- * @return 是否回归上轨下方
- */
- public boolean isReturnFromUpper(BigDecimal price, BigDecimal prevPrice) {
- return prevPrice.compareTo(upper) > 0 && price.compareTo(upper) <= 0;
- }
-
- /**
- * 判断价格是否回归下轨上方
- * @param price 当前价格
- * @param prevPrice 前一期价格
- * @return 是否回归下轨上方
- */
- public boolean isReturnFromLower(BigDecimal price, BigDecimal prevPrice) {
- return prevPrice.compareTo(lower) < 0 && price.compareTo(lower) >= 0;
- }
-
- /**
- * 判断价格是否在中轨上方
- * @param price 当前价格
- * @return 是否在中轨上方
- */
- public boolean isAboveMid(BigDecimal price) {
- return price.compareTo(mid) > 0;
- }
-
- /**
- * 判断价格是否在中轨下方
- * @param price 当前价格
- * @return 是否在中轨下方
- */
- public boolean isBelowMid(BigDecimal price) {
- return price.compareTo(mid) < 0;
- }
-
- /**
- * 计算布林带宽度
- * @return 布林带宽度
- */
- public BigDecimal calculateBandWidth() {
- if (mid.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- }
- return upper.subtract(lower).divide(mid, 8, RoundingMode.HALF_UP);
- }
-
- /**
- * 计算价格相对于布林带的位置
- * @param price 当前价格
- * @return 价格位置指标 (-1: 下轨外, 0: 轨道内, 1: 上轨外)
- */
- public int getPricePosition(BigDecimal price) {
- if (price.compareTo(upper) > 0) {
- return 1;
- } else if (price.compareTo(lower) < 0) {
- return -1;
- } else {
- return 0;
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteStrategyExample.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteStrategyExample.java
deleted file mode 100644
index ed1b226..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteStrategyExample.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 15分钟交易策略使用示例
- * 展示如何使用FifteenMinuteTradingStrategy处理100个15分钟价格数据点
- */
-public class FifteenMinuteStrategyExample {
-
- public static void main(String[] args) {
- // 1. 创建策略实例
- FifteenMinuteTradingStrategy strategy = new FifteenMinuteTradingStrategy();
-
- // 2. 准备100个15分钟价格数据(这里使用模拟数据,用户可以替换为真实数据)
- List<BigDecimal> prices = generateSampleFifteenMinuteData();
- System.out.println("已加载 " + prices.size() + " 个15分钟价格数据点");
-
- // 3. 获取当前价格
- BigDecimal currentPrice = prices.get(prices.size() - 1);
- System.out.println("当前价格: " + currentPrice);
-
- // 4. 示例1:获取多空方向
- System.out.println("\n=== 多空方向分析 ===");
- FifteenMinuteTradingStrategy.Direction direction = strategy.getDirection(prices);
- System.out.println("当前市场方向: " + direction);
-
- // 5. 示例2:获取开仓平仓信号(假设当前没有持仓)
- System.out.println("\n=== 开仓平仓信号分析(无持仓)===");
- FifteenMinuteTradingStrategy.PositionSignal signal1 =
- strategy.getPositionSignal(prices, false, false);
- System.out.println("无持仓时的信号: " + signal1);
-
- // 6. 示例3:获取开仓平仓信号(假设当前持有多仓)
- System.out.println("\n=== 开仓平仓信号分析(持有多仓)===");
- FifteenMinuteTradingStrategy.PositionSignal signal2 =
- strategy.getPositionSignal(prices, true, false);
- System.out.println("持有多仓时的信号: " + signal2);
-
- // 7. 示例4:获取开仓平仓信号(假设当前持有空仓)
- System.out.println("\n=== 开仓平仓信号分析(持有空仓)===");
- FifteenMinuteTradingStrategy.PositionSignal signal3 =
- strategy.getPositionSignal(prices, false, true);
- System.out.println("持有空仓时的信号: " + signal3);
-
- // 8. 示例5:获取完整交易结果
- System.out.println("\n=== 完整交易结果分析 ===");
- FifteenMinuteTradingStrategy.TradingResult result =
- strategy.getTradingResult(prices, false, false);
- System.out.println("市场方向: " + result.getDirection());
- System.out.println("交易信号: " + result.getSignal());
- System.out.println("\n指标状态详情:");
- System.out.println(result.getIndicatorStatus());
- }
-
- /**
- * 生成模拟的15分钟价格数据(100个数据点)
- * 用户可以替换为真实的价格数据
- * @return 15分钟价格数据列表
- */
- private static List<BigDecimal> generateSampleFifteenMinuteData() {
- List<BigDecimal> prices = new ArrayList<>();
-
- // 模拟ETH价格数据(从2400开始,有一定波动)
- BigDecimal basePrice = new BigDecimal(2400);
-
- for (int i = 0; i < 100; i++) {
- // 添加一些随机波动,但保持整体上升趋势
- double random = (Math.random() - 0.48) * 10; // -5 到 5 的随机波动,略微偏向上行
- BigDecimal price = basePrice.add(new BigDecimal(random));
- prices.add(price.setScale(2, BigDecimal.ROUND_HALF_UP));
-
- // 整体缓慢上升
- basePrice = basePrice.add(new BigDecimal(0.2));
- }
-
- return prices;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteTradingExample.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteTradingExample.java
deleted file mode 100644
index d98eccf..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteTradingExample.java
+++ /dev/null
@@ -1,214 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * 15分钟交易策略示例
- * 演示如何使用交易策略与15分钟时间框架数据
- * 展示如何获取方向信号和交易信号
- */
-public class FifteenMinuteTradingExample {
-
- public static void main(String[] args) {
- // 创建交易策略
- TradingStrategy tradingStrategy = new TradingStrategy();
-
- // 生成100个15分钟价格数据点
- List<BigDecimal> prices = generateSampleFifteenMinuteData(100);
-
- // 生成对应的高、低、收盘价数据
- List<BigDecimal> high = generateHighPrices(prices);
- List<BigDecimal> low = generateLowPrices(prices);
- List<BigDecimal> close = new ArrayList<>(prices); // 使用价格作为收盘价
-
- // 生成成交量数据
- List<BigDecimal> volume = generateVolumeData(prices.size());
-
- // 获取最新价格
- BigDecimal currentPrice = prices.get(prices.size() - 1);
-
- // 生成多周期价格数据(5分钟、1小时、4小时)
- List<BigDecimal> fiveMinPrices = generateSampleFifteenMinuteData(100);
- List<BigDecimal> oneHourPrices = generateSampleFifteenMinuteData(100);
- List<BigDecimal> fourHourPrices = generateSampleFifteenMinuteData(100);
-
- // 其他参数
- BigDecimal fundingRate = new BigDecimal("0.001"); // 正常资金费率
- boolean hasLargeTransfer = false; // 无大额转账
- boolean hasUpcomingEvent = false; // 无即将到来的重大事件
-
- // 确定市场方向
- TradingStrategy.Direction direction = tradingStrategy.getDirection(prices, high, low, close, currentPrice);
- System.out.println("市场方向(15分钟): " + direction);
-
- // 检查当前持仓状态
- boolean hasLongPosition = false; // 示例:无当前做多持仓
- boolean hasShortPosition = false; // 示例:无当前做空持仓
-
- // 生成交易信号(开仓/平仓)
- TradingStrategy.SignalType signal = tradingStrategy.generateSignal(prices, high, low, close, volume, currentPrice,
- hasLongPosition, hasShortPosition,
- fiveMinPrices, oneHourPrices, fourHourPrices,
- fundingRate, hasLargeTransfer, hasUpcomingEvent);
- System.out.println("交易信号(15分钟): " + signal);
-
- // 显示指标状态用于分析
- System.out.println("\n指标状态:");
- System.out.println(tradingStrategy.getIndicatorStatus());
-
- // 计算动态杠杆
- BigDecimal dynamicLeverage = tradingStrategy.calculateDynamicLeverage(high, low, close);
- System.out.println("\n动态杠杆倍数: " + dynamicLeverage);
-
- // 基于信号模拟持仓变化
- if (signal == TradingStrategy.SignalType.BUY) {
- System.out.println("\n=== 执行开多操作 ===");
- hasLongPosition = true;
-
- // 演示三段式止盈策略
- BigDecimal entryPrice = currentPrice;
- BigDecimal positionSize = new BigDecimal(100);
- TradingStrategy.ProfitTakingResult profitTakingResult =
- tradingStrategy.calculateThreeStepProfitTaking(entryPrice, currentPrice, direction, positionSize);
- System.out.println("三段式止盈信号: " + profitTakingResult.getSignal());
- System.out.println("应平仓仓位大小: " + profitTakingResult.getClosePositionSize());
- } else if (signal == TradingStrategy.SignalType.SELL) {
- System.out.println("\n=== 执行开空操作 ===");
- hasShortPosition = true;
-
- // 演示三段式止盈策略
- BigDecimal entryPrice = currentPrice;
- BigDecimal positionSize = new BigDecimal(100);
- TradingStrategy.ProfitTakingResult profitTakingResult =
- tradingStrategy.calculateThreeStepProfitTaking(entryPrice, currentPrice, direction, positionSize);
- System.out.println("三段式止盈信号: " + profitTakingResult.getSignal());
- System.out.println("应平仓仓位大小: " + profitTakingResult.getClosePositionSize());
- } else if (signal == TradingStrategy.SignalType.CLOSE_BUY) {
- System.out.println("\n=== 执行平多操作 ===");
- hasLongPosition = false;
- } else if (signal == TradingStrategy.SignalType.CLOSE_SELL) {
- System.out.println("\n=== 执行平空操作 ===");
- hasShortPosition = false;
- } else {
- System.out.println("\n无需交易操作。");
- }
-
- // 现有做多持仓的模拟示例
- System.out.println("\n=== 现有做多持仓的模拟 ===");
- hasLongPosition = true;
- hasShortPosition = false;
- signal = tradingStrategy.generateSignal(prices, high, low, close, volume, currentPrice,
- hasLongPosition, hasShortPosition,
- fiveMinPrices, oneHourPrices, fourHourPrices,
- fundingRate, hasLargeTransfer, hasUpcomingEvent);
- System.out.println("有做多持仓时的交易信号: " + signal);
-
- // 现有做空持仓的模拟示例
- System.out.println("\n=== 现有做空持仓的模拟 ===");
- hasLongPosition = false;
- hasShortPosition = true;
- signal = tradingStrategy.generateSignal(prices, high, low, close, volume, currentPrice,
- hasLongPosition, hasShortPosition,
- fiveMinPrices, oneHourPrices, fourHourPrices,
- fundingRate, hasLargeTransfer, hasUpcomingEvent);
- System.out.println("有做空持仓时的交易信号: " + signal);
-
- // 模拟盈利场景演示三段式止盈
- System.out.println("\n=== 三段式止盈盈利场景演示 ===");
- BigDecimal entryPrice = new BigDecimal(2500.0);
- BigDecimal currentPriceProfit = new BigDecimal(2700.0); // 模拟盈利价格
- BigDecimal positionSize = new BigDecimal(100);
- TradingStrategy.ProfitTakingResult profitTakingResult =
- tradingStrategy.calculateThreeStepProfitTaking(entryPrice, currentPriceProfit, TradingStrategy.Direction.LONG, positionSize);
- System.out.println("入场价格: " + entryPrice);
- System.out.println("当前价格: " + currentPriceProfit);
- System.out.println("三段式止盈信号: " + profitTakingResult.getSignal());
- System.out.println("应平仓仓位大小: " + profitTakingResult.getClosePositionSize());
- }
-
- /**
- * 生成具有真实波动的15分钟价格数据
- * @param size 要生成的数据点数量
- * @return 价格数据列表
- */
- private static List<BigDecimal> generateSampleFifteenMinuteData(int size) {
- List<BigDecimal> prices = new ArrayList<>();
- Random random = new Random();
-
- // 以基础价格开始(ETH示例价格)
- BigDecimal basePrice = new BigDecimal(2500.0);
- prices.add(basePrice);
-
- // 生成具有真实波动的后续价格
- for (int i = 1; i < size; i++) {
- // 创建价格趋势(轻微上升偏向)
- BigDecimal trend = new BigDecimal(0.1).multiply(new BigDecimal(i));
- // 添加随机波动(每个周期±2%)
- BigDecimal volatility = new BigDecimal(random.nextDouble() * 0.04 - 0.02);
- // 计算新价格
- BigDecimal newPrice = basePrice.add(trend).multiply(BigDecimal.ONE.add(volatility));
- // 四舍五入到2位小数
- newPrice = newPrice.setScale(2, BigDecimal.ROUND_HALF_UP);
- prices.add(newPrice);
- }
-
- return prices;
- }
-
- /**
- * 生成最高价数据
- * @param prices 价格数据
- * @return 最高价数据列表
- */
- private static List<BigDecimal> generateHighPrices(List<BigDecimal> prices) {
- List<BigDecimal> high = new ArrayList<>();
- Random random = new Random();
-
- for (BigDecimal price : prices) {
- // 最高价比当前价格高0-2%
- BigDecimal highPrice = price.multiply(BigDecimal.ONE.add(new BigDecimal(random.nextDouble() * 0.02)));
- high.add(highPrice.setScale(2, BigDecimal.ROUND_HALF_UP));
- }
-
- return high;
- }
-
- /**
- * 生成最低价数据
- * @param prices 价格数据
- * @return 最低价数据列表
- */
- private static List<BigDecimal> generateLowPrices(List<BigDecimal> prices) {
- List<BigDecimal> low = new ArrayList<>();
- Random random = new Random();
-
- for (BigDecimal price : prices) {
- // 最低价比当前价格低0-2%
- BigDecimal lowPrice = price.multiply(BigDecimal.ONE.subtract(new BigDecimal(random.nextDouble() * 0.02)));
- low.add(lowPrice.setScale(2, BigDecimal.ROUND_HALF_UP));
- }
-
- return low;
- }
-
- /**
- * 生成成交量数据
- * @param size 数据点数量
- * @return 成交量数据列表
- */
- private static List<BigDecimal> generateVolumeData(int size) {
- List<BigDecimal> volume = new ArrayList<>();
- Random random = new Random();
-
- for (int i = 0; i < size; i++) {
- // 生成1000-10000之间的随机成交量
- BigDecimal vol = new BigDecimal(random.nextInt(9001) + 1000);
- volume.add(vol);
- }
-
- return volume;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteTradingStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteTradingStrategy.java
deleted file mode 100644
index 6510022..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/FifteenMinuteTradingStrategy.java
+++ /dev/null
@@ -1,237 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * 15分钟时间粒度的交易策略实现
- * 专门针对100个15分钟数据点设计的策略,包含明确的多空方向选择和开仓平仓方法
- */
-@Slf4j
-public class FifteenMinuteTradingStrategy {
-
- @Getter
- @Setter
- public static class TradingResult {
- private Direction direction; // 多空方向
- private PositionSignal signal; // 开仓平仓信号
- private String indicatorStatus; // 指标状态
-
- public TradingResult(Direction direction, PositionSignal signal, String indicatorStatus) {
- this.direction = direction;
- this.signal = signal;
- this.indicatorStatus = indicatorStatus;
- }
- }
-
- public enum Direction {
- LONG, // 多头方向
- SHORT, // 空头方向
- RANGING // 震荡行情
- }
-
- public enum PositionSignal {
- OPEN_LONG, // 开多仓
- OPEN_SHORT, // 开空仓
- CLOSE_LONG, // 平多仓
- CLOSE_SHORT, // 平空仓
- HOLD, // 持有
- STAY_OUT // 观望
- }
-
- private final MA ma;
- private final AdvancedMA advancedMA;
- private final BOLL boll;
- private final KDJ kdj;
- private final MACD macd;
- private final RSI rsi;
-
- public FifteenMinuteTradingStrategy() {
- // 15分钟数据优化的参数配置
- this.ma = new MA();
- this.advancedMA = new AdvancedMA();
- this.boll = new BOLL(20, 2.0); // BOLL使用默认20周期
- this.kdj = new KDJ(9); // KDJ使用默认9周期
- this.macd = new MACD(); // MACD使用默认12/26/9周期
- this.rsi = new RSI(14); // RSI使用默认14周期
- }
-
- /**
- * 计算所有指标
- * @param prices 15分钟价格数据(至少100个数据点)
- */
- private void calculateIndicators(List<BigDecimal> prices) {
- ma.calculate(prices);
- advancedMA.calculateTripleEMA(prices);
- boll.calculate(prices);
- kdj.calculate(prices);
- macd.calculate(prices);
- rsi.calculate(prices);
- }
-
- /**
- * 判断市场是否处于震荡行情
- * @return 是否为震荡行情
- */
- private boolean isRangeMarket() {
- // AdvancedMA三线粘合 + RSI(40-60) + BOLL带宽收窄
- boolean isMaConverged = advancedMA.calculatePercent().compareTo(new BigDecimal(2)) < 0;
- boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(40)) > 0 &&
- rsi.getRsi().compareTo(new BigDecimal(60)) < 0;
- boolean isBollNarrow = boll.calculateBandWidth().compareTo(new BigDecimal(0.05)) < 0;
-
- return isMaConverged && isRsiNeutral && isBollNarrow;
- }
-
- /**
- * 获取多空方向选择
- * @param prices 15分钟价格数据(100个数据点)
- * @return 多空方向
- */
- public Direction getDirection(List<BigDecimal> prices) {
- if (prices == null || prices.size() < 100) {
- throw new IllegalArgumentException("需要至少100个15分钟价格数据点");
- }
-
- calculateIndicators(prices);
-
- // 震荡过滤
- if (isRangeMarket()) {
- return Direction.RANGING;
- }
-
- BigDecimal currentPrice = prices.get(prices.size() - 1);
-
- // 多头信号判断:MA多头排列 + MACD金叉 + RSI(30-70) + BOLL价格在上轨与中轨之间
- boolean isLongSignal =
- ma.getEma5().compareTo(ma.getEma10()) > 0 && // MA5 > MA10
- ma.getEma10().compareTo(ma.getEma20()) > 0 && // MA10 > MA20
- macd.getDif().compareTo(macd.getDea()) > 0 && // MACD金叉
- rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0 && // RSI(30-70)
- currentPrice.compareTo(boll.getMid()) > 0 && currentPrice.compareTo(boll.getUpper()) < 0; // BOLL价格在上轨与中轨之间
-
- // 空头信号判断:MA空头排列 + MACD死叉 + RSI(30-70) + BOLL价格在下轨与中轨之间
- boolean isShortSignal =
- ma.getEma5().compareTo(ma.getEma10()) < 0 && // MA5 < MA10
- ma.getEma10().compareTo(ma.getEma20()) < 0 && // MA10 < MA20
- macd.getDif().compareTo(macd.getDea()) < 0 && // MACD死叉
- rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0 && // RSI(30-70)
- currentPrice.compareTo(boll.getMid()) < 0 && currentPrice.compareTo(boll.getLower()) > 0; // BOLL价格在下轨与中轨之间
-
- if (isLongSignal) {
- return Direction.LONG;
- } else if (isShortSignal) {
- return Direction.SHORT;
- } else {
- return Direction.RANGING;
- }
- }
-
- /**
- * 获取开仓平仓策略信号
- * @param prices 15分钟价格数据(100个数据点)
- * @param hasLongPosition 当前是否持有多仓
- * @param hasShortPosition 当前是否持有空仓
- * @return 开仓平仓信号
- */
- public PositionSignal getPositionSignal(List<BigDecimal> prices, boolean hasLongPosition, boolean hasShortPosition) {
- if (prices == null || prices.size() < 100) {
- throw new IllegalArgumentException("需要至少100个15分钟价格数据点");
- }
-
- calculateIndicators(prices);
-
- // 震荡过滤
- if (isRangeMarket()) {
- return PositionSignal.STAY_OUT;
- }
-
- BigDecimal currentPrice = prices.get(prices.size() - 1);
-
- // 开多信号:MA金叉 + MACD金叉 + KDJ金叉 + RSI中性 + 价格在BOLL中轨上方
- boolean shouldOpenLong =
- ma.getEma5().compareTo(ma.getEma20()) > 0 && // MA金叉(5日EMA上穿20日EMA)
- macd.getDif().compareTo(macd.getDea()) > 0 && macd.getMacdBar().compareTo(BigDecimal.ZERO) > 0 && // MACD金叉且柱状图为正
- kdj.isGoldenCross() && // KDJ金叉
- rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0 && // RSI中性
- currentPrice.compareTo(boll.getMid()) > 0; // 价格在BOLL中轨上方
-
- // 开空信号:MA死叉 + MACD死叉 + KDJ死叉 + RSI中性 + 价格在BOLL中轨下方
- boolean shouldOpenShort =
- ma.getEma5().compareTo(ma.getEma20()) < 0 && // MA死叉(5日EMA下穿20日EMA)
- macd.getDif().compareTo(macd.getDea()) < 0 && macd.getMacdBar().compareTo(BigDecimal.ZERO) < 0 && // MACD死叉且柱状图为负
- kdj.isDeathCross() && // KDJ死叉
- rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0 && // RSI中性
- currentPrice.compareTo(boll.getMid()) < 0; // 价格在BOLL中轨下方
-
- // 平多信号:MA死叉 + MACD死叉 + RSI超买 + 价格跌破BOLL中轨
- boolean shouldCloseLong =
- (ma.getEma5().compareTo(ma.getEma20()) < 0 && // MA死叉
- macd.getDif().compareTo(macd.getDea()) < 0 && // MACD死叉
- (rsi.isOverbought() || rsi.isExtremelyOverbought())) || // RSI超买
- currentPrice.compareTo(boll.getMid()) < 0; // 价格跌破BOLL中轨
-
- // 平空信号:MA金叉 + MACD金叉 + RSI超卖 + 价格突破BOLL中轨
- boolean shouldCloseShort =
- (ma.getEma5().compareTo(ma.getEma20()) > 0 && // MA金叉
- macd.getDif().compareTo(macd.getDea()) > 0 && // MACD金叉
- (rsi.isOversold() || rsi.isExtremelyOversold())) || // RSI超卖
- currentPrice.compareTo(boll.getMid()) > 0; // 价格突破BOLL中轨
-
- // 确定开仓信号
- if (shouldOpenLong && !hasLongPosition && !hasShortPosition) {
- return PositionSignal.OPEN_LONG;
- } else if (shouldOpenShort && !hasLongPosition && !hasShortPosition) {
- return PositionSignal.OPEN_SHORT;
- }
-
- // 确定平仓信号
- if (shouldCloseLong && hasLongPosition) {
- return PositionSignal.CLOSE_LONG;
- } else if (shouldCloseShort && hasShortPosition) {
- return PositionSignal.CLOSE_SHORT;
- }
-
- // 无信号
- return hasLongPosition || hasShortPosition ? PositionSignal.HOLD : PositionSignal.STAY_OUT;
- }
-
- /**
- * 综合获取交易结果
- * @param prices 15分钟价格数据(100个数据点)
- * @param hasLongPosition 当前是否持有多仓
- * @param hasShortPosition 当前是否持有空仓
- * @return 包含多空方向和开仓平仓信号的完整交易结果
- */
- public TradingResult getTradingResult(List<BigDecimal> prices, boolean hasLongPosition, boolean hasShortPosition) {
- Direction direction = getDirection(prices);
- PositionSignal signal = getPositionSignal(prices, hasLongPosition, hasShortPosition);
- String indicatorStatus = getIndicatorStatus();
-
- return new TradingResult(direction, signal, indicatorStatus);
- }
-
- /**
- * 获取当前指标状态
- * @return 指标状态字符串
- */
- private String getIndicatorStatus() {
- return String.format("MA5: %s, MA20: %s, " +
- "MACD-DIF: %s, MACD-DEA: %s, MACD-BAR: %s, " +
- "KDJ-K: %s, KDJ-D: %s, KDJ-J: %s, " +
- "RSI: %s, " +
- "BOLL-UP: %s, BOLL-MID: %s, BOLL-DN: %s, " +
- "AdvancedMA-Bullish: %s, Bearish: %s, Percent: %s",
- ma.getEma5(), ma.getEma20(),
- macd.getDif(), macd.getDea(), macd.getMacdBar(),
- kdj.getK(), kdj.getD(), kdj.getJ(),
- rsi.getRsi(),
- boll.getUpper(), boll.getMid(), boll.getLower(),
- advancedMA.isBullish(), advancedMA.isBearish(), advancedMA.calculatePercent());
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java
deleted file mode 100644
index a3b80b7..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Technical indicators base class, provides common calculation methods
- *
- * Indicator combination strategy:
- * 1. Trend judgment (MA/AdvancedMA/MACD): Determine the overall trend direction of prices
- * 2. Momentum confirmation (RSI/KDJ): Confirm the strength and sustainability of the current trend
- * 3. Volatility reference (BOLL): Determine reasonable price volatility range and breakthrough timing
- *
- * Long/Short direction selection logic:
- * - Long signal: MA bullish arrangement + MACD golden cross + RSI(30-70) + BOLL price between upper and middle band
- * - Short signal: MA bearish arrangement + MACD death cross + RSI(30-70) + BOLL price between lower and middle band
- * - Consolidation signal: AdvancedMA three-line convergence + RSI(40-60) + BOLL bandwidth narrowing
- *
- * Open and close position strategies:
- * - Open long: MA golden cross + MACD golden cross + KDJ golden cross + RSI(30-70) + price breaks through BOLL middle band
- * - Open short: MA death cross + MACD death cross + KDJ death cross + RSI(30-70) + price breaks below BOLL middle band
- * - Close long: MA death cross + MACD death cross + RSI overbought(>70) + price breaks below BOLL middle band
- * - Close short: MA golden cross + MACD golden cross + RSI oversold(<30) + price breaks through BOLL middle band
- */
-public abstract class IndicatorBase {
-
- /**
- * Calculate moving average
- * @param prices Price list
- * @param period Period
- * @return Moving average value
- */
- protected BigDecimal calculateMA(List<BigDecimal> prices, int period) {
- if (prices == null || prices.size() < period) {
- return BigDecimal.ZERO;
- }
- BigDecimal sum = BigDecimal.ZERO;
- for (int i = prices.size() - period; i < prices.size(); i++) {
- sum = sum.add(prices.get(i));
- }
- return sum.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
- }
-
- /**
- * Calculate exponential moving average
- * @param prices Price list
- * @param period Period
- * @param prevEMA Previous EMA value
- * @return Exponential moving average value
- */
- protected BigDecimal calculateEMA(List<BigDecimal> prices, int period, BigDecimal prevEMA) {
- if (prices == null || prices.size() == 0) {
- return BigDecimal.ZERO;
- }
- if (prevEMA == null || prevEMA.compareTo(BigDecimal.ZERO) == 0) {
- return calculateMA(prices, Math.min(period, prices.size()));
- }
- BigDecimal k = new BigDecimal(2).divide(new BigDecimal(period + 1), 8, RoundingMode.HALF_UP);
- BigDecimal currentPrice = prices.get(prices.size() - 1);
- return currentPrice.multiply(k).add(prevEMA.multiply(BigDecimal.ONE.subtract(k)));
- }
-
- /**
- * Calculate standard deviation
- * @param prices Price list
- * @param period Period
- * @return Standard deviation
- */
- protected BigDecimal calculateStdDev(List<BigDecimal> prices, int period) {
- if (prices == null || prices.size() < period) {
- return BigDecimal.ZERO;
- }
- BigDecimal ma = calculateMA(prices, period);
- BigDecimal sumSquares = BigDecimal.ZERO;
- for (int i = prices.size() - period; i < prices.size(); i++) {
- BigDecimal diff = prices.get(i).subtract(ma);
- sumSquares = sumSquares.add(diff.multiply(diff));
- }
- BigDecimal variance = sumSquares.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
- return sqrt(variance);
- }
-
- /**
- * Calculate square root (simplified implementation)
- * @param value Input value
- * @return Square root
- */
- protected BigDecimal sqrt(BigDecimal value) {
- if (value.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimal.ZERO;
- }
- return new BigDecimal(Math.sqrt(value.doubleValue())).setScale(8, RoundingMode.HALF_UP);
- }
-
- /**
- * Get recent price data
- * @param prices All price data
- * @param period Period
- * @return Recent period price data
- */
- protected List<BigDecimal> getRecentPrices(List<BigDecimal> prices, int period) {
- if (prices == null || prices.size() == 0) {
- return new ArrayList<>();
- }
- int startIndex = Math.max(0, prices.size() - period);
- return prices.subList(startIndex, prices.size());
- }
-
- /**
- * Calculate ATR (Average True Range)
- * @param high High price list
- * @param low Low price list
- * @param close Close price list
- * @param period Period
- * @return ATR value
- */
- protected BigDecimal calculateATR(List<BigDecimal> high, List<BigDecimal> low, List<BigDecimal> close, int period) {
- if (high == null || low == null || close == null ||
- high.size() < period || low.size() < period || close.size() < period) {
- return BigDecimal.ZERO;
- }
-
- List<BigDecimal> trList = new ArrayList<>();
- for (int i = 1; i < high.size(); i++) {
- BigDecimal trueRange = calculateTrueRange(high.get(i), low.get(i), close.get(i - 1));
- trList.add(trueRange);
- }
-
- // Use simple moving average to calculate ATR
- return calculateMA(trList, Math.min(period, trList.size()));
- }
-
- /**
- * Calculate True Range
- * @param high Current high price
- * @param low Current low price
- * @param prevClose Previous close price
- * @return True range
- */
- protected BigDecimal calculateTrueRange(BigDecimal high, BigDecimal low, BigDecimal prevClose) {
- BigDecimal h1 = high.subtract(low);
- BigDecimal h2 = high.subtract(prevClose).abs();
- BigDecimal h3 = low.subtract(prevClose).abs();
- return h1.max(h2).max(h3);
- }
-
- /**
- * Calculate normalized volatility (based on ATR)
- * @param close Close price list
- * @param atr ATR value
- * @return Normalized volatility (percentage)
- */
- protected BigDecimal normalizeVolatility(List<BigDecimal> close, BigDecimal atr) {
- if (close == null || close.size() == 0 || atr.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- }
- return atr.divide(close.get(close.size() - 1), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/KDJ.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/KDJ.java
deleted file mode 100644
index 7148f4e..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/KDJ.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.List;
-
-/**
- * KDJ (Stochastic Oscillator) 指标实现
- * 计算逻辑:
- * 1. RSV = (收盘价 - N日内最低价) / (N日内最高价 - N日内最低价) * 100
- * 2. K = 2/3 * 前一日K值 + 1/3 * 当日RSV
- * 3. D = 2/3 * 前一日D值 + 1/3 * 当日K值
- * 4. J = 3*K - 2*D
- *
- * 作用:
- * 1. 衡量价格的超买超卖状态(K值>80超买,K值<20超卖)
- * 2. K线上穿D线形成金叉,提示买入信号
- * 3. K线下穿D线形成死叉,提示卖出信号
- * 4. J值反映市场的极端状态,J值>100或J值<0为极端行情
- *
- * 价格参数类型:
- * - 参数名称:prices
- * - 参数类型:List<BigDecimal>
- * - 参数说明:需要至少9个(默认周期)价格数据点用于计算
- *
- * 推荐时间粒度及优缺点:
- * 1. 1分钟(1m):
- * - 优点:反应迅速,适合超短线交易
- * - 缺点:K值波动剧烈,信号频繁且可靠性低
- * 2. 5分钟(5m):
- * - 优点:K值波动相对稳定,适合短线交易
- * - 缺点:仍有一定虚假信号
- * 3. 15分钟(15m):
- * - 优点:信号较为可靠,适合日内交易
- * - 缺点:反应速度较慢
- * 4. 1小时(1h)及以上:
- * - 优点:超买超卖信号明确,适合中期交易
- * - 缺点:反应滞后,不适合短线交易
- */
-@Slf4j
-@Getter
-@Setter
-public class KDJ extends IndicatorBase {
-
- private static final int DEFAULT_PERIOD = 9;
- private static final int K_PERIOD = 3;
- private static final int D_PERIOD = 3;
-
- private int period = DEFAULT_PERIOD;
- private BigDecimal k = new BigDecimal(50);
- private BigDecimal d = new BigDecimal(50);
- private BigDecimal j = new BigDecimal(50);
- private BigDecimal prevK = new BigDecimal(50);
- private BigDecimal prevD = new BigDecimal(50);
-
- public KDJ() {}
-
- public KDJ(int period) {
- this.period = period;
- }
-
- /**
- * 计算KDJ指标
- * @param prices 价格列表
- */
- public void calculate(List<BigDecimal> prices) {
- if (prices == null || prices.size() < period) {
- return;
- }
-
- // 获取最近N天的价格
- List<BigDecimal> recentPrices = getRecentPrices(prices, period);
-
- // 计算最高价和最低价
- BigDecimal high = recentPrices.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
- BigDecimal low = recentPrices.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
- BigDecimal close = recentPrices.get(recentPrices.size() - 1);
-
- // 计算RSV
- BigDecimal rsv;
- if (high.compareTo(low) == 0) {
- rsv = new BigDecimal(50);
- } else {
- rsv = close.subtract(low)
- .divide(high.subtract(low), 8, RoundingMode.HALF_UP)
- .multiply(new BigDecimal(100))
- .setScale(8, RoundingMode.HALF_UP);
- }
-
- // 计算K值
- prevK = k;
- k = new BigDecimal(2).multiply(prevK)
- .add(rsv)
- .divide(new BigDecimal(3), 8, RoundingMode.HALF_UP);
-
- // 计算D值
- prevD = d;
- d = new BigDecimal(2).multiply(prevD)
- .add(k)
- .divide(new BigDecimal(3), 8, RoundingMode.HALF_UP);
-
- // 计算J值
- j = k.multiply(new BigDecimal(3))
- .subtract(d.multiply(new BigDecimal(2)))
- .setScale(8, RoundingMode.HALF_UP);
-
- log.info("KDJ计算结果 - K: {}, D: {}, J: {}", k, d, j);
- }
-
- /**
- * 判断超买(J > 85)
- * @return 是否超买
- */
- public boolean isOverbought() {
- return j.compareTo(new BigDecimal(85)) > 0;
- }
-
- /**
- * 判断超卖(J < 15)
- * @return 是否超卖
- */
- public boolean isOversold() {
- return j.compareTo(new BigDecimal(15)) < 0;
- }
-
- /**
- * 判断金叉信号(K线上穿D线)
- * @return 是否形成金叉
- */
- public boolean isGoldenCross() {
- return prevK.compareTo(prevD) < 0 && k.compareTo(d) > 0;
- }
-
- /**
- * 判断死叉信号(K线下穿D线)
- * @return 是否形成死叉
- */
- public boolean isDeathCross() {
- return prevK.compareTo(prevD) > 0 && k.compareTo(d) < 0;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MA.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MA.java
deleted file mode 100644
index 0da46e6..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MA.java
+++ /dev/null
@@ -1,232 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * MA (Moving Average) 指标实现
- * 支持不同周期的简单移动平均线(SMA)和指数移动平均线(EMA)
- *
- * 作用:
- * 1. 平滑价格波动,识别趋势方向
- * 2. 短周期MA上穿长周期MA形成金叉,提示买入信号
- * 3. 短周期MA下穿长周期MA形成死叉,提示卖出信号
- * 4. 价格上穿/下穿MA线,也可作为买卖参考
- *
- * 价格参数类型:
- * - 参数名称:prices
- * - 参数类型:List<BigDecimal>
- * - 参数说明:需要至少1个价格数据点用于计算,根据不同周期需求更多数据点
- *
- * 推荐时间粒度及优缺点:
- * 1. 1分钟(1m):
- * - 优点:反应迅速,适合超短线交易
- * - 缺点:噪音多,容易产生虚假信号
- * 2. 5分钟(5m):
- * - 优点:平衡了反应速度和噪音过滤
- * - 缺点:仍有一定噪音
- * 3. 15分钟(15m):
- * - 优点:适合日内交易,信号相对可靠
- * - 缺点:反应速度较慢
- * 4. 1小时(1h)及以上:
- * - 优点:趋势信号明确,虚假信号少
- * - 缺点:反应滞后,不适合短线交易
- */
-@Slf4j
-@Getter
-@Setter
-public class MA extends IndicatorBase {
-
- // 默认周期
- public static final int DEFAULT_MA5 = 5;
- public static final int DEFAULT_MA10 = 10;
- public static final int DEFAULT_MA20 = 20;
- public static final int DEFAULT_MA30 = 30;
- public static final int DEFAULT_MA60 = 60;
-
- // 动态周期参数
- private int ma5Period;
- private int ma10Period;
- private int ma20Period;
- private int ma30Period;
- private int ma60Period;
-
- private BigDecimal ma5 = BigDecimal.ZERO;
- private BigDecimal ma10 = BigDecimal.ZERO;
- private BigDecimal ma20 = BigDecimal.ZERO;
- private BigDecimal ma30 = BigDecimal.ZERO;
- private BigDecimal ma60 = BigDecimal.ZERO;
-
- private BigDecimal ema5 = BigDecimal.ZERO;
- private BigDecimal ema10 = BigDecimal.ZERO;
- private BigDecimal ema20 = BigDecimal.ZERO;
- private BigDecimal ema30 = BigDecimal.ZERO;
- private BigDecimal ema60 = BigDecimal.ZERO;
-
- private BigDecimal prevEma5 = null;
- private BigDecimal prevEma10 = null;
- private BigDecimal prevEma20 = null;
- private BigDecimal prevEma30 = null;
- private BigDecimal prevEma60 = null;
-
- // 构造函数使用默认周期
- public MA() {
- this.ma5Period = DEFAULT_MA5;
- this.ma10Period = DEFAULT_MA10;
- this.ma20Period = DEFAULT_MA20;
- this.ma30Period = DEFAULT_MA30;
- this.ma60Period = DEFAULT_MA60;
- }
-
- /**
- * 计算所有周期的MA指标(使用当前周期设置)
- * @param prices 价格列表
- */
- public void calculate(List<BigDecimal> prices) {
- calculate(prices, null);
- }
-
- /**
- * 计算所有周期的MA指标,并支持动态周期调整
- * @param prices 价格列表
- * @param volatility 标准化波动率(ATR百分比),用于动态调整周期
- */
- public void calculate(List<BigDecimal> prices, BigDecimal volatility) {
- if (prices == null || prices.size() < 1) {
- return;
- }
-
- // 如果提供了波动率,则动态调整周期
- if (volatility != null) {
- adjustPeriodsByVolatility(volatility);
- }
-
- // 计算SMA
- if (prices.size() >= ma5Period) {
- ma5 = calculateMA(prices, ma5Period);
- }
- if (prices.size() >= ma10Period) {
- ma10 = calculateMA(prices, ma10Period);
- }
- if (prices.size() >= ma20Period) {
- ma20 = calculateMA(prices, ma20Period);
- }
- if (prices.size() >= ma30Period) {
- ma30 = calculateMA(prices, ma30Period);
- }
- if (prices.size() >= ma60Period) {
- ma60 = calculateMA(prices, ma60Period);
- }
-
- // 计算EMA
- prevEma5 = calculateEMA(prices, ma5Period, prevEma5);
- ema5 = prevEma5;
-
- prevEma10 = calculateEMA(prices, ma10Period, prevEma10);
- ema10 = prevEma10;
-
- prevEma20 = calculateEMA(prices, ma20Period, prevEma20);
- ema20 = prevEma20;
-
- prevEma30 = calculateEMA(prices, ma30Period, prevEma30);
- ema30 = prevEma30;
-
- prevEma60 = calculateEMA(prices, ma60Period, prevEma60);
- ema60 = prevEma60;
-
- log.info("MA计算结果 - MA5({}): {}, MA10({}): {}, MA20({}): {}, MA30({}): {}, MA60({}): {}",
- ma5Period, ma5, ma10Period, ma10, ma20Period, ma20, ma30Period, ma30, ma60Period, ma60);
- log.info("EMA计算结果 - EMA5({}): {}, EMA10({}): {}, EMA20({}): {}, EMA30({}): {}, EMA60({}): {}",
- ma5Period, ema5, ma10Period, ema10, ma20Period, ema20, ma30Period, ema30, ma60Period, ema60);
- }
-
- /**
- * 根据波动率调整MA周期
- * @param volatility 标准化波动率(ATR百分比)
- */
- private void adjustPeriodsByVolatility(BigDecimal volatility) {
- // 根据波动率缩放均线周期
- // 3%、5%、8%作为ATR阈值
- BigDecimal lowVolatility = new BigDecimal(3);
- BigDecimal midVolatility = new BigDecimal(5);
- BigDecimal highVolatility = new BigDecimal(8);
-
- // 快速MA周期 (ma5)
- ma5Period = volatility.compareTo(lowVolatility) < 0 ? 10 : 6;
-
- // 中期MA周期 (ma10, ma20)
- ma10Period = volatility.compareTo(midVolatility) < 0 ? 10 : 8;
- ma20Period = volatility.compareTo(midVolatility) < 0 ? 21 : 13;
-
- // 长期MA周期 (ma30, ma60)
- ma30Period = volatility.compareTo(highVolatility) < 0 ? 30 : 24;
- ma60Period = volatility.compareTo(highVolatility) < 0 ? 50 : 34;
-
- log.info("根据波动率{}调整MA周期: ma5={}, ma10={}, ma20={}, ma30={}, ma60={}",
- volatility, ma5Period, ma10Period, ma20Period, ma30Period, ma60Period);
- }
-
- /**
- * 判断短期均线是否上穿长期均线(金叉)
- * @param shortMA 短期均线
- * @param longMA 长期均线
- * @param prevShortMA 前一期短期均线
- * @param prevLongMA 前一期长期均线
- * @return 是否形成金叉
- */
- public boolean isGoldenCross(BigDecimal shortMA, BigDecimal longMA,
- BigDecimal prevShortMA, BigDecimal prevLongMA) {
- return prevShortMA != null && prevLongMA != null &&
- prevShortMA.compareTo(prevLongMA) < 0 &&
- shortMA.compareTo(longMA) > 0;
- }
-
- /**
- * 判断短期均线是否下穿长期均线(死叉)
- * @param shortMA 短期均线
- * @param longMA 长期均线
- * @param prevShortMA 前一期短期均线
- * @param prevLongMA 前一期长期均线
- * @return 是否形成死叉
- */
- public boolean isDeathCross(BigDecimal shortMA, BigDecimal longMA,
- BigDecimal prevShortMA, BigDecimal prevLongMA) {
- return prevShortMA != null && prevLongMA != null &&
- prevShortMA.compareTo(prevLongMA) > 0 &&
- shortMA.compareTo(longMA) < 0;
- }
-
- /**
- * 判断价格是否上穿均线
- * @param price 当前价格
- * @param ma 均线值
- * @param prevPrice 前一期价格
- * @param prevMA 前一期均线值
- * @return 是否上穿
- */
- public boolean isPriceCrossUp(BigDecimal price, BigDecimal ma,
- BigDecimal prevPrice, BigDecimal prevMA) {
- return prevPrice != null && prevMA != null &&
- prevPrice.compareTo(prevMA) < 0 &&
- price.compareTo(ma) > 0;
- }
-
- /**
- * 判断价格是否下穿均线
- * @param price 当前价格
- * @param ma 均线值
- * @param prevPrice 前一期价格
- * @param prevMA 前一期均线值
- * @return 是否下穿
- */
- public boolean isPriceCrossDown(BigDecimal price, BigDecimal ma,
- BigDecimal prevPrice, BigDecimal prevMA) {
- return prevPrice != null && prevMA != null &&
- prevPrice.compareTo(prevMA) > 0 &&
- price.compareTo(ma) < 0;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MACD.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MACD.java
deleted file mode 100644
index 9b63ee2..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MACD.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.Getter;
-import lombok.Setter;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * MACD (Moving Average Convergence Divergence) 指标实现
- * 计算逻辑:
- * 1. 快线DIFF = EMA(Close, 12) - EMA(Close, 26)
- * 2. 慢线DEA = EMA(DIFF, 9)
- * 3. MACD柱状图 = (DIFF - DEA) * macdBarsMultiplier
- *
- * 核心概念:
- * 1. DIFF是EMA12与EMA26之间的距离,反映短期与长期趋势的差异
- * 2. 当DIFF > 0表示EMA12在EMA26上方,代表多头趋势
- * 3. 当DIFF < 0表示EMA12在EMA26下方,代表空头趋势
- * 4. DEA是DIFF的EMA平滑线,用于过滤DIFF的波动
- * 5. MACD柱状图通过放大倍数展示DIFF与DEA之间的关系,便于观察趋势变化
- *
- * 多空判断:
- * - 多头机会:DIFF在0轴上且MACD柱状图向上,股价同步上涨
- * - 空头机会:DIFF在0轴下且MACD柱状图向下,股价同步下跌
- *
- * 信号过滤:
- * - 可通过设置macdBarsSmoothingPeriod启用MACD柱状图平滑处理
- * - 平滑公式:MACD柱状图 = MA((DIFF - DEA) * macdBarsMultiplier, macdBarsSmoothingPeriod)
- * - 作用:消除柱状图杂讯,使信号更加清晰
- */
-@Getter
-@Setter
-public class MACD extends IndicatorBase {
-
- // 默认周期参数
- public static final int DEFAULT_FAST_PERIOD = 12;
- public static final int DEFAULT_SLOW_PERIOD = 26;
- public static final int DEFAULT_SIGNAL_PERIOD = 9;
-
- // 默认MACD柱状图放大倍数
- public static final int DEFAULT_MACDBARS_MULTIPLIER = 2;
- // 默认MACD柱状图平滑周期(0表示不平滑)
- public static final int DEFAULT_MACDBARS_SMOOTHING_PERIOD = 0;
-
- // 周期参数
- private int fastPeriod;
- private int slowPeriod;
- private int signalPeriod;
-
- // MACD柱状图参数
- private int macdBarsMultiplier; // MACD柱状图放大倍数
- private int macdBarsSmoothingPeriod; // MACD柱状图平滑周期(0表示不平滑)
-
- // MACD计算结果
- private BigDecimal dif = BigDecimal.ZERO;
- private BigDecimal dea = BigDecimal.ZERO;
- private BigDecimal macdBar = BigDecimal.ZERO;
-
- // 历史值缓存
- private BigDecimal prevFastEMA = null;
- private BigDecimal prevSlowEMA = null;
- private BigDecimal prevDea = null;
- private List<BigDecimal> difHistory = new ArrayList<>(); // 保存历史DIF值,用于计算DEA
- private List<BigDecimal> rawMacdBarHistory = new ArrayList<>(); // 保存原始MACD柱状图值,用于平滑处理
-
- // 最大保存的历史值数量
- private static final int MAX_HISTORY_SIZE = 50;
-
- // 构造函数使用默认参数
- public MACD() {
- this.fastPeriod = DEFAULT_FAST_PERIOD;
- this.slowPeriod = DEFAULT_SLOW_PERIOD;
- this.signalPeriod = DEFAULT_SIGNAL_PERIOD;
- this.macdBarsMultiplier = DEFAULT_MACDBARS_MULTIPLIER;
- this.macdBarsSmoothingPeriod = DEFAULT_MACDBARS_SMOOTHING_PERIOD;
- }
-
- /**
- * 计算MACD指标(使用当前周期设置)
- * @param prices 价格列表
- */
- public void calculate(List<BigDecimal> prices) {
- calculate(prices, null);
- }
-
- /**
- * 计算MACD指标,并支持动态周期调整
- * @param prices 价格列表
- * @param volatility 标准化波动率(百分比),用于动态调整周期
- */
- public void calculate(List<BigDecimal> prices, BigDecimal volatility) {
- if (prices == null || prices.isEmpty()) {
- return;
- }
-
- // 如果提供了波动率,则动态调整周期
- if (volatility != null) {
- adjustPeriodsByVolatility(volatility);
- }
-
-
-
- // 计算快速EMA (12日)
- prevFastEMA = calculateEMA(prices, fastPeriod, prevFastEMA);
-
- // 计算慢速EMA (26日)
- prevSlowEMA = calculateEMA(prices, slowPeriod, prevSlowEMA);
-
- // 计算DIF = EMA(12) - EMA(26)
- dif = prevFastEMA.subtract(prevSlowEMA).setScale(8, RoundingMode.HALF_UP);
-
- // 将新的DIF值添加到历史记录
- difHistory.add(dif);
- // 保持历史记录在合理范围内
- if (difHistory.size() > MAX_HISTORY_SIZE) {
- difHistory.remove(0);
- }
-
- // 计算DEA = EMA(DIFF, 9)
- calculateDEA();
-
- // 计算原始MACD柱状图值 = (DIF - DEA) * 放大倍数
- BigDecimal rawMacdBar = dif.subtract(dea).multiply(new BigDecimal(macdBarsMultiplier)).setScale(8, RoundingMode.HALF_UP);
-
- // 将原始MACD柱状图值添加到历史记录
- rawMacdBarHistory.add(rawMacdBar);
- // 保持历史记录在合理范围内
- if (rawMacdBarHistory.size() > MAX_HISTORY_SIZE) {
- rawMacdBarHistory.remove(0);
- }
-
- // 如果启用了平滑处理,则计算平滑后的MACD柱状图
- if (macdBarsSmoothingPeriod > 0) {
- macdBar = smoothMacdBars().setScale(8, RoundingMode.HALF_UP);
- } else {
- macdBar = rawMacdBar;
- }
-
-
- }
-
- /**
- * 计算DEA指标
- */
- private void calculateDEA() {
- int difCount = difHistory.size();
-
- // 如果没有足够的DIF历史值,无法计算有效的DEA
- if (difCount == 0) {
- dea = BigDecimal.ZERO;
- prevDea = null;
- return;
- }
-
- // 计算DEA = EMA(DIFF, signalPeriod)
- // 使用所有DIF历史值来计算初始EMA,然后使用最新值更新
- prevDea = calculateEMA(difHistory, signalPeriod, prevDea);
- dea = prevDea.setScale(8, RoundingMode.HALF_UP);
- }
-
- /**
- * 平滑MACD柱状图
- * @return 平滑后的MACD柱状图值
- */
- private BigDecimal smoothMacdBars() {
- int historyCount = rawMacdBarHistory.size();
-
- // 如果没有足够的历史数据,返回最新的原始值
- if (historyCount < macdBarsSmoothingPeriod) {
- return rawMacdBarHistory.get(historyCount - 1);
- }
-
- // 使用简单移动平均平滑MACD柱状图
- List<BigDecimal> recentMacdBars = rawMacdBarHistory.subList(historyCount - macdBarsSmoothingPeriod, historyCount);
- return calculateMA(recentMacdBars, macdBarsSmoothingPeriod);
- }
-
- /**
- * 根据波动率调整MACD周期参数
- * @param volatility 标准化波动率(百分比)
- */
- private void adjustPeriodsByVolatility(BigDecimal volatility) {
- // 波动率阈值
- BigDecimal volatilityThreshold = new BigDecimal(15);
-
- // 根据波动率调整MACD参数
- if (volatility.compareTo(volatilityThreshold) < 0) {
- // 低波动率环境,使用默认参数
- fastPeriod = DEFAULT_FAST_PERIOD;
- slowPeriod = DEFAULT_SLOW_PERIOD;
- signalPeriod = DEFAULT_SIGNAL_PERIOD;
- } else {
- // 高波动率环境,使用更灵敏的参数
- fastPeriod = 8;
- slowPeriod = 17;
- signalPeriod = 5;
- }
-
-
- }
-
- /**
- * 判断金叉信号(DIF上穿DEA)
- * @param previousDIF 上一个DIF值
- * @param previousDEA 上一个DEA值
- * @return 是否形成金叉
- */
- public boolean isGoldenCross(BigDecimal previousDIF, BigDecimal previousDEA) {
- return previousDIF != null && previousDEA != null &&
- previousDIF.compareTo(previousDEA) < 0 && dif.compareTo(dea) > 0;
- }
-
- /**
- * 判断死叉信号(DIF下穿DEA)
- * @param previousDIF 上一个DIF值
- * @param previousDEA 上一个DEA值
- * @return 是否形成死叉
- */
- public boolean isDeathCross(BigDecimal previousDIF, BigDecimal previousDEA) {
- return previousDIF != null && previousDEA != null &&
- previousDIF.compareTo(previousDEA) > 0 && dif.compareTo(dea) < 0;
- }
-
- /**
- * 重置MACD指标状态
- */
- public void reset() {
- dif = BigDecimal.ZERO;
- dea = BigDecimal.ZERO;
- macdBar = BigDecimal.ZERO;
- prevFastEMA = null;
- prevSlowEMA = null;
- prevDea = null;
- difHistory.clear();
- rawMacdBarHistory.clear();
-
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MACDTest.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MACDTest.java
deleted file mode 100644
index ec93614..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MACDTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * MACD Indicator Test Class
- * Used to verify the correctness of MACD calculation logic
- */
-public class MACDTest {
-
- public static void main(String[] args) {
- // Create MACD instance
- MACD macd = new MACD();
-
- // Set MACD bars parameters (optional, using default values here)
- macd.setMacdBarsMultiplier(2); // Default multiplier
- macd.setMacdBarsSmoothingPeriod(0); // No smoothing
-
- // Generate test price data (simple upward trend)
- List<BigDecimal> prices = generateTestPrices(30);
-
- System.out.println("=== MACD Indicator Test Start ===");
- System.out.println("Price count: " + prices.size());
- System.out.println("MACD parameters: fast=" + macd.getFastPeriod() + ", slow=" + macd.getSlowPeriod() + ", signal=" + macd.getSignalPeriod());
- System.out.println("MACD bars parameters: multiplier=" + macd.getMacdBarsMultiplier() + ", smoothing=" + macd.getMacdBarsSmoothingPeriod());
- System.out.println();
-
- // Calculate MACD
- macd.calculate(prices);
-
- // Output results
- System.out.println("=== MACD Calculation Results ===");
- System.out.println("DIF: " + macd.getDif());
- System.out.println("DEA: " + macd.getDea());
- System.out.println("MACD Bars: " + macd.getMacdBar());
- System.out.println();
-
- // Trend judgment
- System.out.println("=== Trend Judgment ===");
- if (macd.getDif().compareTo(BigDecimal.ZERO) > 0) {
- System.out.println("DIFF > 0: Bullish trend");
- } else if (macd.getDif().compareTo(BigDecimal.ZERO) < 0) {
- System.out.println("DIFF < 0: Bearish trend");
- } else {
- System.out.println("DIFF = 0: No trend");
- }
-
- // Test smoothing function
- testSmoothingFunction();
-
- System.out.println("=== MACD Indicator Test End ===");
- }
-
- /**
- * Generate test price data
- * @param count Number of data points
- * @return Price list
- */
- private static List<BigDecimal> generateTestPrices(int count) {
- List<BigDecimal> prices = new ArrayList<>();
- // Start from 100, simple upward trend with some random fluctuations
- BigDecimal basePrice = new BigDecimal(100);
- for (int i = 0; i < count; i++) {
- // Add random fluctuation between 0.1 and 0.5
- BigDecimal price = basePrice.add(new BigDecimal(Math.random() * 0.4 + 0.1));
- prices.add(price.setScale(2, BigDecimal.ROUND_HALF_UP));
- basePrice = price;
- }
- return prices;
- }
-
- /**
- * Test MACD bars smoothing function
- */
- private static void testSmoothingFunction() {
- System.out.println("=== MACD Bars Smoothing Function Test ===");
-
- MACD macd = new MACD();
- macd.setMacdBarsMultiplier(2);
- macd.setMacdBarsSmoothingPeriod(3); // 3-day smoothing
-
- // Generate test price data with more fluctuations
- List<BigDecimal> prices = generateVolatileTestPrices(30);
-
- macd.calculate(prices);
-
- System.out.println("Price count: " + prices.size());
- System.out.println("MACD parameters: fast=" + macd.getFastPeriod() + ", slow=" + macd.getSlowPeriod() + ", signal=" + macd.getSignalPeriod());
- System.out.println("MACD bars parameters: multiplier=" + macd.getMacdBarsMultiplier() + ", smoothing=" + macd.getMacdBarsSmoothingPeriod());
- System.out.println();
-
- System.out.println("Smoothed MACD Results:");
- System.out.println("DIF: " + macd.getDif());
- System.out.println("DEA: " + macd.getDea());
- System.out.println("MACD Bars: " + macd.getMacdBar());
- System.out.println();
- }
-
- /**
- * Generate test price data with more fluctuations
- * @param count Number of data points
- * @return Price list
- */
- private static List<BigDecimal> generateVolatileTestPrices(int count) {
- List<BigDecimal> prices = new ArrayList<>();
- // Start from 100 with more random fluctuations
- BigDecimal basePrice = new BigDecimal(100);
- for (int i = 0; i < count; i++) {
- // Add random fluctuation between -1.0 and 1.0
- BigDecimal price = basePrice.add(new BigDecimal(Math.random() * 2 - 1));
- prices.add(price.setScale(2, BigDecimal.ROUND_HALF_UP));
- basePrice = price;
- }
- return prices;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/RSI.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/RSI.java
deleted file mode 100644
index 3e05082..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/RSI.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.List;
-
-/**
- * RSI (Relative Strength Index) 指标实现
- * 计算逻辑:
- * 1. 计算N天内的上涨幅度和下跌幅度
- * 2. 计算平均上涨幅度和平均下跌幅度
- * 3. RSI = 100 - (100 / (1 + (平均上涨幅度 / 平均下跌幅度)))
- *
- * 作用:
- * 1. 衡量市场的相对强弱程度(0-100)
- * 2. 超买信号:RSI>70表示市场超买,可能回调
- * 3. 超卖信号:RSI<30表示市场超卖,可能反弹
- * 4. 极端超买:RSI>80表示市场极度超买
- * 5. 极端超卖:RSI<20表示市场极度超卖
- *
- * 价格参数类型:
- * - 参数名称:prices
- * - 参数类型:List<BigDecimal>
- * - 参数说明:需要至少15个(默认周期+1)价格数据点用于计算
- *
- * 推荐时间粒度及优缺点:
- * 1. 1分钟(1m):
- * - 优点:反应迅速,适合超短线交易
- * - 缺点:RSI波动剧烈,频繁进入超买超卖区域
- * 2. 5分钟(5m):
- * - 优点:RSI波动相对稳定,适合短线交易
- * - 缺点:仍有一定虚假超买超卖信号
- * 3. 15分钟(15m):
- * - 优点:超买超卖信号较为可靠,适合日内交易
- * - 缺点:反应速度较慢
- * 4. 1小时(1h)及以上:
- * - 优点:超买超卖信号明确,适合中期交易
- * - 缺点:反应滞后,不适合短线交易
- */
-@Slf4j
-@Getter
-@Setter
-public class RSI extends IndicatorBase {
-
- private static final int DEFAULT_PERIOD = 14;
-
- private int period = DEFAULT_PERIOD;
- private BigDecimal rsi = BigDecimal.ZERO;
- private BigDecimal prevAvgGain = BigDecimal.ZERO;
- private BigDecimal prevAvgLoss = BigDecimal.ZERO;
-
- public RSI() {}
-
- public RSI(int period) {
- this.period = period;
- }
-
- /**
- * 计算RSI指标
- * @param prices 价格列表
- */
- public void calculate(List<BigDecimal> prices) {
- if (prices == null || prices.size() < period + 1) {
- return;
- }
-
- if (prevAvgGain.compareTo(BigDecimal.ZERO) == 0 && prevAvgLoss.compareTo(BigDecimal.ZERO) == 0) {
- // 首次计算
- BigDecimal totalGain = BigDecimal.ZERO;
- BigDecimal totalLoss = BigDecimal.ZERO;
-
- for (int i = prices.size() - period; i < prices.size(); i++) {
- BigDecimal change = prices.get(i).subtract(prices.get(i - 1));
- if (change.compareTo(BigDecimal.ZERO) > 0) {
- totalGain = totalGain.add(change);
- } else {
- totalLoss = totalLoss.add(change.abs());
- }
- }
-
- prevAvgGain = totalGain.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
- prevAvgLoss = totalLoss.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
- } else {
- // 后续计算
- BigDecimal change = prices.get(prices.size() - 1).subtract(prices.get(prices.size() - 2));
- BigDecimal gain = change.compareTo(BigDecimal.ZERO) > 0 ? change : BigDecimal.ZERO;
- BigDecimal loss = change.compareTo(BigDecimal.ZERO) < 0 ? change.abs() : BigDecimal.ZERO;
-
- prevAvgGain = prevAvgGain.multiply(new BigDecimal(period - 1))
- .add(gain)
- .divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
- prevAvgLoss = prevAvgLoss.multiply(new BigDecimal(period - 1))
- .add(loss)
- .divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
- }
-
- // 计算RSI
- if (prevAvgLoss.compareTo(BigDecimal.ZERO) == 0) {
- rsi = new BigDecimal(100);
- } else {
- BigDecimal rs = prevAvgGain.divide(prevAvgLoss, 8, RoundingMode.HALF_UP);
- rsi = new BigDecimal(100)
- .subtract(new BigDecimal(100).divide(BigDecimal.ONE.add(rs), 8, RoundingMode.HALF_UP))
- .setScale(8, RoundingMode.HALF_UP);
- }
-
- log.info("RSI计算结果 - RSI({}): {}", period, rsi);
- }
-
- /**
- * 判断超买(RSI > 70)
- * @return 是否超买
- */
- public boolean isOverbought() {
- return rsi.compareTo(new BigDecimal(70)) > 0;
- }
-
- /**
- * 判断超卖(RSI < 30)
- * @return 是否超卖
- */
- public boolean isOversold() {
- return rsi.compareTo(new BigDecimal(30)) < 0;
- }
-
- /**
- * 判断超买(RSI > 80)
- * @return 是否严重超买
- */
- public boolean isExtremelyOverbought() {
- return rsi.compareTo(new BigDecimal(80)) > 0;
- }
-
- /**
- * 判断超卖(RSI < 20)
- * @return 是否严重超卖
- */
- public boolean isExtremelyOversold() {
- return rsi.compareTo(new BigDecimal(20)) < 0;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java
deleted file mode 100644
index 558ad79..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java
+++ /dev/null
@@ -1,1029 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 交易策略实现
- * 展示如何为ETH合约交易(开仓/平仓)组合所有指标
- */
-@Slf4j
-public class TradingStrategy extends IndicatorBase {
-
- @Getter
- @Setter
- @AllArgsConstructor
- @NoArgsConstructor
- public static class StrategyConfig {
- private int maShortPeriod = 5; // 短期移动平均周期
- private int maLongPeriod = 20; // 长期移动平均周期
- private int rsiPeriod = 14; // RSI指标周期
- private int kdjPeriod = 9; // KDJ指标周期
- private int bollPeriod = 20; // 布林带周期
- private double bollK = 2.0; // 布林带标准差倍数
- private int atrPeriod = 14; // ATR计算周期
- private boolean enableDynamicParams = true; // 是否启用动态参数优化
- private boolean enableMultiTimeframeConfirm = true; // 是否启用多周期确认
- private int volumeMaPeriod = 20; // 成交量移动平均周期
- private boolean enableVolumeConfirm = true; // 是否启用成交量验证
-
- // 风险控制参数
- private BigDecimal baseLeverage = new BigDecimal(3); // 基础杠杆倍数
- private int volatilityThresholdPeriod = 30; // 波动率阈值计算周期(用于动态杠杆)
- private boolean enableDynamicLeverage = true; // 是否启用动态杠杆
- private boolean enableThreeStepProfitTaking = true; // 是否启用三段式止盈
- private boolean enableBlackSwanFilter = true; // 是否启用黑天鹅事件过滤
- }
-
- public enum Direction {
- LONG, // 做多方向信号
- SHORT, // 做空方向信号
- RANGING // 震荡市场
- }
-
- public enum SignalType {
- NONE, // 无信号
- BUY, // 开多信号
- SELL, // 开空信号
- CLOSE_BUY, // 平多信号
- CLOSE_SELL // 平空信号
- }
-
- private final StrategyConfig config;
- private final MA ma;
- private final AdvancedMA advancedMA;
- private final BOLL boll;
- private final KDJ kdj;
- private final MACD macd;
- private final RSI rsi;
-
- public TradingStrategy() {
- this(new StrategyConfig());
- }
-
- public TradingStrategy(StrategyConfig config) {
- this.config = config;
- this.ma = new MA();
- this.advancedMA = new AdvancedMA();
- this.boll = new BOLL(config.getBollPeriod(), config.getBollK());
- this.kdj = new KDJ(config.getKdjPeriod());
- this.macd = new MACD();
- this.rsi = new RSI(config.getRsiPeriod());
- }
-
- /**
- * 计算所有指标并生成交易信号
- * @param prices 价格数据
- * @param high 最高价列表
- * @param low 最低价列表
- * @param close 收盘价列表
- * @param volume 成交量列表
- * @param currentPrice 当前价格
- * @param hasLongPosition 是否当前持有做多仓位
- * @param hasShortPosition 是否当前持有做空仓位
- * @param fiveMinPrices 5分钟价格数据(多周期确认)
- * @param oneHourPrices 1小时价格数据(多周期确认)
- * @param fourHourPrices 4小时价格数据(多周期确认)
- * @param fundingRate 当前资金费率(用于黑天鹅过滤)
- * @param hasLargeTransfer 是否有大额转账(用于黑天鹅过滤)
- * @param hasUpcomingEvent 是否有即将到来的重大事件(用于黑天鹅过滤)
- * @return 交易信号
- */
- public SignalType generateSignal(List<BigDecimal> prices, List<BigDecimal> high,
- List<BigDecimal> low, List<BigDecimal> close,
- List<BigDecimal> volume, BigDecimal currentPrice,
- boolean hasLongPosition, boolean hasShortPosition,
- List<BigDecimal> fiveMinPrices,
- List<BigDecimal> oneHourPrices,
- List<BigDecimal> fourHourPrices,
- BigDecimal fundingRate,
- boolean hasLargeTransfer,
- boolean hasUpcomingEvent) {
- // 计算所有指标
- calculateIndicators(prices, high, low, close);
-
- // 检查是否为震荡市场,如果是,则执行区间交易策略
- if (isRangeMarket(prices)) {
- log.info("当前市场为震荡行情,执行区间交易策略");
- return generateRangeTradingSignal(currentPrice, volume, hasLongPosition, hasShortPosition);
- }
-
- // 黑天鹅事件过滤
- if (blackSwanFilter(fundingRate, hasLargeTransfer, hasUpcomingEvent)) {
- log.info("黑天鹅事件过滤触发,不产生信号");
- return SignalType.NONE;
- }
-
- // 开多信号
- if (shouldOpenLong(currentPrice, prices, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) {
- log.info("生成买入信号");
- return SignalType.BUY;
- }
-
- // 开空信号
- if (shouldOpenShort(currentPrice, prices, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) {
- log.info("生成卖出信号");
- return SignalType.SELL;
- }
-
- // 平多信号
- if (shouldCloseLong(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && hasLongPosition) {
- log.info("生成平多信号");
- return SignalType.CLOSE_BUY;
- }
-
- // 平空信号
- if (shouldCloseShort(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && hasShortPosition) {
- log.info("生成平空信号");
- return SignalType.CLOSE_SELL;
- }
-
- log.info("未生成信号");
- return SignalType.NONE;
- }
-
- /**
- * 多周期确认辅助方法(看涨)
- * @param fiveMinPrices 5分钟价格数据
- * @param oneHourPrices 1小时价格数据
- * @param fourHourPrices 4小时价格数据
- * @return 是否有足够的多周期确认
- */
- private boolean multiTimeframeConfirm(List<BigDecimal> fiveMinPrices,
- List<BigDecimal> oneHourPrices,
- List<BigDecimal> fourHourPrices) {
- if (!config.isEnableMultiTimeframeConfirm()) {
- return true; // 如果未启用多周期确认,则默认返回true
- }
-
- int confirmCount = 0;
-
- // 检查5分钟周期
- if (hasBullishTrend(fiveMinPrices)) {
- confirmCount++;
- }
-
- // 检查1小时周期
- if (hasBullishTrend(oneHourPrices)) {
- confirmCount++;
- }
-
- // 检查4小时周期
- if (hasBullishTrend(fourHourPrices)) {
- confirmCount++;
- }
-
- // 至少需要2个周期确认
- return confirmCount >= 2;
- }
-
- /**
- * 多周期确认辅助方法(看跌)
- * @param fiveMinPrices 5分钟价格数据
- * @param oneHourPrices 1小时价格数据
- * @param fourHourPrices 4小时价格数据
- * @return 是否有足够的多周期确认
- */
- private boolean multiTimeframeBearishConfirm(List<BigDecimal> fiveMinPrices,
- List<BigDecimal> oneHourPrices,
- List<BigDecimal> fourHourPrices) {
- if (!config.isEnableMultiTimeframeConfirm()) {
- return true; // 如果未启用多周期确认,则默认返回true
- }
-
- int confirmCount = 0;
-
- // 检查5分钟周期
- if (hasBearishTrend(fiveMinPrices)) {
- confirmCount++;
- }
-
- // 检查1小时周期
- if (hasBearishTrend(oneHourPrices)) {
- confirmCount++;
- }
-
- // 检查4小时周期
- if (hasBearishTrend(fourHourPrices)) {
- confirmCount++;
- }
-
- // 至少需要2个周期确认
- return confirmCount >= 2;
- }
-
- /**
- * 检查指定周期是否有看涨趋势
- * @param prices 价格数据
- * @return 是否有看涨趋势
- */
- private boolean hasBullishTrend(List<BigDecimal> prices) {
- if (prices == null || prices.size() < 20) {
- return false; // 数据不足
- }
-
- // 创建临时MA指标用于判断趋势
- MA tempMA = new MA();
- MACD tempMACD = new MACD();
-
- // 计算指标
- tempMA.calculate(prices);
- tempMACD.calculate(prices);
-
- // 优化后的多头趋势判断:
- // 1. MA多头排列:短期MA > 中期MA > 长期MA
- // 2. 所有均线向上发散
- // 3. MACD趋势:DIFF线在DEA线之上
- boolean isMaBullish = tempMA.getEma5().compareTo(tempMA.getEma10()) > 0 &&
- tempMA.getEma10().compareTo(tempMA.getEma20()) > 0;
-
- // 判断均线向上发散(简单方法:近期均线斜率为正)
- boolean isMaDivergingUp = calculateMaSlope(prices, 5) > 0 &&
- calculateMaSlope(prices, 10) > 0 &&
- calculateMaSlope(prices, 20) > 0;
-
- // MACD趋势判断
- boolean isMacdBullish = tempMACD.getDif().compareTo(tempMACD.getDea()) > 0;
-
- return isMaBullish && isMaDivergingUp && isMacdBullish;
- }
-
- /**
- * 检查指定周期是否有看跌趋势
- * @param prices 价格数据
- * @return 是否有看跌趋势
- */
- private boolean hasBearishTrend(List<BigDecimal> prices) {
- if (prices == null || prices.size() < 20) {
- return false; // 数据不足
- }
-
- // 创建临时MA指标用于判断趋势
- MA tempMA = new MA();
- MACD tempMACD = new MACD();
-
- // 计算指标
- tempMA.calculate(prices);
- tempMACD.calculate(prices);
-
- // 优化后的空头趋势判断:
- // 1. MA空头排列:短期MA < 中期MA < 长期MA
- // 2. 所有均线向下发散
- // 3. MACD趋势:DIFF线在DEA线之下
- boolean isMaBearish = tempMA.getEma5().compareTo(tempMA.getEma10()) < 0 &&
- tempMA.getEma10().compareTo(tempMA.getEma20()) < 0;
-
- // 判断均线向下发散(简单方法:近期均线斜率为负)
- boolean isMaDivergingDown = calculateMaSlope(prices, 5) < 0 &&
- calculateMaSlope(prices, 10) < 0 &&
- calculateMaSlope(prices, 20) < 0;
-
- // MACD趋势判断
- boolean isMacdBearish = tempMACD.getDif().compareTo(tempMACD.getDea()) < 0;
-
- return isMaBearish && isMaDivergingDown && isMacdBearish;
- }
-
- /**
- * 计算均线斜率
- * @param prices 价格数据
- * @param period 均线周期
- * @return 均线斜率(正数表示向上,负数表示向下)
- */
- private double calculateMaSlope(List<BigDecimal> prices, int period) {
- if (prices == null || prices.size() < period * 2) {
- return 0; // 数据不足
- }
-
- // 获取最近两个周期的均线值
- int endIndex = prices.size() - 1;
- int startIndex = endIndex - period + 1;
-
- // 计算当前周期的均线
- BigDecimal currentMa = calculateMA(prices.subList(startIndex, endIndex + 1), period);
-
- // 计算前一个周期的均线
- int prevStartIndex = startIndex - period;
- BigDecimal prevMa = calculateMA(prices.subList(prevStartIndex, startIndex), period);
-
- // 计算斜率(简单差值法)
- return currentMa.subtract(prevMa).doubleValue();
- }
-
- /**
- * 成交量验证辅助方法
- * 增强版:当前成交量需大于20周期均量的1.2倍,以过滤无量反弹/回调的假信号
- * @param volume 成交量列表
- * @return 是否通过成交量验证
- */
- private boolean volumeConfirm(List<BigDecimal> volume) {
- if (!config.isEnableVolumeConfirm() || volume == null || volume.size() < config.getVolumeMaPeriod()) {
- return true; // 如果未启用成交量验证或数据不足,则默认返回true
- }
-
- // 计算成交量移动平均
- BigDecimal volumeMA = calculateMA(volume, config.getVolumeMaPeriod());
- BigDecimal currentVolume = volume.get(volume.size() - 1);
-
- // 增强验证:成交量需要大于1.2倍均线
- return currentVolume.compareTo(volumeMA.multiply(new BigDecimal("1.2"))) > 0;
- }
-
- /**
- * 量价背离检测
- * 检测价格上涨/下跌但成交量萎缩的情况,或价格和成交量趋势不一致
- * @param prices 价格列表
- * @param volume 成交量列表
- * @return 是否存在量价背离
- */
- private boolean hasPriceVolumeDivergence(List<BigDecimal> prices, List<BigDecimal> volume) {
- if (!config.isEnableVolumeConfirm() || prices == null || volume == null || prices.size() < 3 || volume.size() < 3) {
- return false; // 如果未启用成交量验证或数据不足,则默认返回false
- }
-
- // 获取最近3个周期的价格和成交量
- BigDecimal currentPrice = prices.get(prices.size() - 1);
- BigDecimal prevPrice1 = prices.get(prices.size() - 2);
- BigDecimal prevPrice2 = prices.get(prices.size() - 3);
-
- BigDecimal currentVolume = volume.get(volume.size() - 1);
- BigDecimal prevVolume1 = volume.get(volume.size() - 2);
- BigDecimal prevVolume2 = volume.get(volume.size() - 3);
-
- // 计算价格趋势
- boolean priceTrendUp = currentPrice.compareTo(prevPrice1) > 0 && prevPrice1.compareTo(prevPrice2) > 0;
- boolean priceTrendDown = currentPrice.compareTo(prevPrice1) < 0 && prevPrice1.compareTo(prevPrice2) < 0;
-
- // 计算成交量趋势
- boolean volumeTrendUp = currentVolume.compareTo(prevVolume1) > 0 && prevVolume1.compareTo(prevVolume2) > 0;
- boolean volumeTrendDown = currentVolume.compareTo(prevVolume1) < 0 && prevVolume1.compareTo(prevVolume2) < 0;
-
- // 检测量价背离
- // 价格上涨但成交量萎缩
- boolean bullishDivergence = priceTrendUp && volumeTrendDown;
- // 价格下跌但成交量萎缩(通常是强势信号,不视为背离)
- // 价格下跌但成交量放大(可能是恐慌性抛售,视为背离)
- boolean bearishDivergence = priceTrendDown && volumeTrendUp;
-
- return bullishDivergence || bearishDivergence;
- }
-
- /**
- * 计算所有指标
- * @param prices 价格数据
- * @param high 最高价列表
- * @param low 最低价列表
- * @param close 收盘价列表
- */
- private void calculateIndicators(List<BigDecimal> prices, List<BigDecimal> high,
- List<BigDecimal> low, List<BigDecimal> close) {
- // 计算ATR和波动率
- BigDecimal atr = calculateATR(high, low, close, config.getAtrPeriod());
- BigDecimal volatility = normalizeVolatility(close, atr);
-
- // 使用动态参数计算指标
- if (config.isEnableDynamicParams()) {
- log.info("使用动态参数计算指标,波动率: {}", volatility);
- ma.calculate(prices, volatility);
- macd.calculate(prices, volatility);
- } else {
- ma.calculate(prices);
- macd.calculate(prices);
- }
-
- // 其他指标计算
- advancedMA.calculateTripleEMA(prices);
- boll.calculate(prices);
- kdj.calculate(prices);
- rsi.calculate(prices);
- }
-
- /**
- * 检查是否为震荡市场
- * @param prices 价格数据列表
- * @return 是否为震荡市场
- */
- private boolean isRangeMarket(List<BigDecimal> prices) {
- // 优化的震荡市场判断条件,放宽标准以减少RANGING信号频率
-
- // 1. 高级MA三线收敛(小于3%,放宽条件)
- boolean isMaConverged = advancedMA.calculatePercent().compareTo(new BigDecimal(3)) < 0;
-
- // 2. RSI中性区间(35-65,放宽条件)
- boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(35)) > 0 &&
- rsi.getRsi().compareTo(new BigDecimal(65)) < 0;
-
- // 3. BOLL带宽收窄(小于0.06,放宽条件)
- boolean isBollNarrow = boll.calculateBandWidth().compareTo(new BigDecimal(0.06)) < 0;
-
- // 4. MACD柱状图趋近于0(多空力量平衡,放宽条件)
- boolean isMacdBalanced = macd.getMacdBar().abs().compareTo(new BigDecimal(0.02)) < 0;
-
- // 5. KDJ在中间区域波动(25-75,放宽条件)
- boolean isKdjNeutral = kdj.getK().compareTo(new BigDecimal(25)) > 0 &&
- kdj.getK().compareTo(new BigDecimal(75)) < 0 &&
- kdj.getD().compareTo(new BigDecimal(25)) > 0 &&
- kdj.getD().compareTo(new BigDecimal(75)) < 0 &&
- kdj.getJ().compareTo(new BigDecimal(20)) > 0 &&
- kdj.getJ().compareTo(new BigDecimal(80)) < 0;
-
- // 6. 价格波动范围较小(最近20根K线最高价与最低价的比值小于1.06,放宽条件)
- boolean isPriceVolatilityLow = calculatePriceVolatility(prices).compareTo(new BigDecimal(1.06)) < 0;
-
- // 综合判断:只需要满足部分条件即可,增加趋势信号的机会
- int rangeConditionsMet = 0;
- if (isMaConverged) {
- rangeConditionsMet++;
- }
- if (isRsiNeutral) {
- rangeConditionsMet++;
- }
- if (isBollNarrow) {
- rangeConditionsMet++;
- }
- if (isMacdBalanced) {
- rangeConditionsMet++;
- }
- if (isKdjNeutral) {
- rangeConditionsMet++;
- }
- if (isPriceVolatilityLow) {
- rangeConditionsMet++;
- }
-
- // 只有满足4个或以上条件才判定为震荡市场
- return rangeConditionsMet >= 4;
- }
-
- /**
- * 计算价格波动率(最近20根K线最高价与最低价的比值)
- * @param prices 价格数据列表
- * @return 价格波动率
- */
- private BigDecimal calculatePriceVolatility(List<BigDecimal> prices) {
- if (prices == null || prices.isEmpty()) {
- return BigDecimal.ONE;
- }
-
- List<BigDecimal> recentPrices = prices.subList(Math.max(0, prices.size() - 20), prices.size());
- if (recentPrices.isEmpty()) {
- return BigDecimal.ONE;
- }
-
- BigDecimal highest = recentPrices.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ONE);
- BigDecimal lowest = recentPrices.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ONE);
-
- return highest.divide(lowest, 10, RoundingMode.HALF_UP);
- }
-
-
-
- /**
- * 根据15分钟时间框架指标确定市场方向(做多/做空/震荡)
- * @param prices 价格数据列表
- * @param high 最高价列表
- * @param low 最低价列表
- * @param close 收盘价列表
- * @param currentPrice 当前价格
- * @return 市场方向
- */
- public Direction getDirection(List<BigDecimal> prices, List<BigDecimal> high,
- List<BigDecimal> low, List<BigDecimal> close,
- BigDecimal currentPrice) {
- // 计算所有指标
- calculateIndicators(prices, high, low, close);
-
- // 检查是否为震荡市场
- if (isRangeMarket(prices)) {
- return Direction.RANGING;
- }
-
- // 优化后的多头趋势条件:
- // 1. MA多头排列(短期MA > 中期MA > 长期MA)
- // 2. MACD趋势(DIFF在DEA之上,代表多头趋势)
- // 3. 价格在BOLL中轨上方
- // 4. RSI(50-65) 为健康多头区间
- boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 &&
- ma.getEma10().compareTo(ma.getEma20()) > 0;
- boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0;
- boolean isPriceAboveBollMid = currentPrice.compareTo(boll.getMid()) > 0;
- boolean isRsiBullish = rsi.getRsi().compareTo(new BigDecimal(50)) > 0 &&
- rsi.getRsi().compareTo(new BigDecimal(65)) < 0;
-
- // 检查多头信号(MA多头 + MACD金叉 + 价格在BOLL中轨上方 + RSI(50-65))
- if (isMaBullish && isMacdBullish && isPriceAboveBollMid && isRsiBullish) {
- return Direction.LONG;
- }
-
- // 优化后的空头趋势条件:
- // 1. MA空头排列(短期MA < 中期MA < 长期MA)
- // 2. MACD趋势(DIFF在DEA之下,代表空头趋势)
- // 3. 价格在BOLL中轨下方
- // 4. RSI(35-50) 为健康空头区间
- boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 &&
- ma.getEma10().compareTo(ma.getEma20()) < 0;
- boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0;
- boolean isPriceBelowBollMid = currentPrice.compareTo(boll.getMid()) < 0;
- boolean isRsiBearish = rsi.getRsi().compareTo(new BigDecimal(35)) > 0 &&
- rsi.getRsi().compareTo(new BigDecimal(50)) < 0;
-
- // 检查空头信号(MA空头 + MACD死叉 + 价格在BOLL中轨下方 + RSI(35-50))
- if (isMaBearish && isMacdBearish && isPriceBelowBollMid && isRsiBearish) {
- return Direction.SHORT;
- }
-
- // 如果没有明确方向,默认为震荡
- return Direction.RANGING;
- }
-
- /**
- * 根据优化建议检查是否应该开多仓位
- * 使用主次结合法:
- * - 主信号(趋势):MA多头排列 + MACD金叉
- * - 辅信号(入场点):价格回调至BOLL中轨附近获得支撑,且出现KDJ金叉或RSI从低位回升至50以上
- * @param currentPrice 当前价格
- * @param prices 价格数据
- * @param volume 成交量列表
- * @param fiveMinPrices 5分钟价格数据
- * @param oneHourPrices 1小时价格数据
- * @param fourHourPrices 4小时价格数据
- * @return 是否应该开多
- */
- private boolean shouldOpenLong(BigDecimal currentPrice, List<BigDecimal> prices, List<BigDecimal> volume,
- List<BigDecimal> fiveMinPrices,
- List<BigDecimal> oneHourPrices,
- List<BigDecimal> fourHourPrices) {
- // 主信号:趋势判断
- // MA多头排列(短期MA > 中期MA > 长期MA)
- boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 &&
- ma.getEma10().compareTo(ma.getEma20()) > 0;
- // MACD趋势(DIFF在DEA之上)
- boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0;
-
- // 如果主信号不满足,直接返回false
- if (!(isMaBullish && isMacdBullish)) {
- return false;
- }
-
- // 辅信号:入场点判断
- // 价格在BOLL中轨上方,且未触及上轨(避免追高)
- boolean isPriceInSafeZone = currentPrice.compareTo(boll.getMid()) > 0 &&
- currentPrice.compareTo(boll.getUpper()) < 0;
- // 价格靠近BOLL中轨
- boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(0.98))) > 0 &&
- currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(1.02))) < 0;
-
- // RSI:健康区间30-70,刚从50中线向上
- boolean isRsiHealthy = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 &&
- rsi.getRsi().compareTo(new BigDecimal(70)) < 0;
- boolean isRsiAboveMid = rsi.getRsi().compareTo(new BigDecimal(50)) > 0;
-
- // KDJ:金叉或超卖区域
- boolean isKdjGoldenCross = kdj.isGoldenCross();
- boolean isKdjOversold = kdj.getJ().compareTo(new BigDecimal(15)) < 0;
-
- // 入场点条件:价格在安全区域或靠近中轨,且动量健康
- boolean isEntryPointValid = (isPriceInSafeZone || isPriceNearBollMid) &&
- (isRsiHealthy && isRsiAboveMid) &&
- (isKdjGoldenCross || isKdjOversold);
-
- // 成交量验证
- boolean isVolumeConfirmed = volumeConfirm(volume);
- // 量价背离检测
- boolean isPriceVolumeDivergence = hasPriceVolumeDivergence(prices, volume);
- // 多周期确认
- boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
-
- return isEntryPointValid && isVolumeConfirmed && !isPriceVolumeDivergence && isMultiTimeframeConfirmed;
- }
-
- /**
- * 根据优化建议检查是否应该开空仓位
- * 使用主次结合法:
- * - 主信号(趋势):MA空头排列 + MACD死叉
- * - 辅信号(入场点):价格反弹至BOLL中轨附近遇阻,且出现KDJ死叉或RSI从高位回落至50以下
- * @param currentPrice 当前价格
- * @param prices 价格数据
- * @param volume 成交量列表
- * @param fiveMinPrices 5分钟价格数据
- * @param oneHourPrices 1小时价格数据
- * @param fourHourPrices 4小时价格数据
- * @return 是否应该开空
- */
- private boolean shouldOpenShort(BigDecimal currentPrice, List<BigDecimal> prices, List<BigDecimal> volume,
- List<BigDecimal> fiveMinPrices,
- List<BigDecimal> oneHourPrices,
- List<BigDecimal> fourHourPrices) {
- // 主信号:趋势判断
- // MA空头排列(短期MA < 中期MA < 长期MA)
- boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 &&
- ma.getEma10().compareTo(ma.getEma20()) < 0;
- // MACD趋势(DIFF在DEA之下)
- boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0;
-
- // 如果主信号不满足,直接返回false
- if (!(isMaBearish && isMacdBearish)) {
- return false;
- }
-
- // 辅信号:入场点判断
- // 价格在BOLL中轨下方,且未触及下轨(避免追空)
- boolean isPriceInSafeZone = currentPrice.compareTo(boll.getMid()) < 0 &&
- currentPrice.compareTo(boll.getLower()) > 0;
- // 价格靠近BOLL中轨
- boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(0.98))) > 0 &&
- currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(1.02))) < 0;
-
- // RSI:健康区间30-70,刚从50中线向下
- boolean isRsiHealthy = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 &&
- rsi.getRsi().compareTo(new BigDecimal(70)) < 0;
- boolean isRsiBelowMid = rsi.getRsi().compareTo(new BigDecimal(50)) < 0;
-
- // KDJ:死叉或超买区域
- boolean isKdjDeathCross = kdj.isDeathCross();
- boolean isKdjOverbought = kdj.getJ().compareTo(new BigDecimal(85)) > 0;
-
- // 入场点条件:价格在安全区域或靠近中轨,且动量健康
- boolean isEntryPointValid = (isPriceInSafeZone || isPriceNearBollMid) &&
- (isRsiHealthy && isRsiBelowMid) &&
- (isKdjDeathCross || isKdjOverbought);
-
- // 成交量验证
- boolean isVolumeConfirmed = volumeConfirm(volume);
- // 量价背离检测
- boolean isPriceVolumeDivergence = hasPriceVolumeDivergence(prices, volume);
- // 多周期确认(看跌)
- boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
-
- return isEntryPointValid && isVolumeConfirmed && !isPriceVolumeDivergence && isMultiTimeframeConfirmed;
- }
-
- /**
- * 根据优化建议检查是否应该平多仓位
- * 采用分层止盈止损策略:
- * - 保护止损:价格跌破BOLL中轨
- * - 跟踪止损:价格有效跌破移动平均线
- * - 最终平仓:趋势反转信号(MA空头排列 + MACD死叉)
- * @param currentPrice 当前价格
- * @param volume 成交量列表
- * @param fiveMinPrices 5分钟价格数据
- * @param oneHourPrices 1小时价格数据
- * @param fourHourPrices 4小时价格数据
- * @return 是否应该平多
- */
- private boolean shouldCloseLong(BigDecimal currentPrice, List<BigDecimal> volume,
- List<BigDecimal> fiveMinPrices,
- List<BigDecimal> oneHourPrices,
- List<BigDecimal> fourHourPrices) {
- // 保护止损:价格跌破BOLL中轨(关键支撑位)
- boolean isStopLossTriggered = currentPrice.compareTo(boll.getMid()) < 0;
-
- // 跟踪止损:价格有效跌破短期均线(5EMA)
- boolean isTrailingStopTriggered = currentPrice.compareTo(ma.getEma5()) < 0;
-
- // 趋势反转信号:MA空头排列 + MACD死叉
- boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 &&
- ma.getEma10().compareTo(ma.getEma20()) < 0;
- boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0;
- boolean isTrendReversed = isMaBearish && isMacdBearish;
-
- // 多周期确认(看跌)
- boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
-
- // 平多条件:保护止损触发 或 跟踪止损触发 或 (趋势反转且多周期确认)
- return isStopLossTriggered || isTrailingStopTriggered || (isTrendReversed && isMultiTimeframeConfirmed);
- }
-
- /**
- * 根据优化建议检查是否应该平空仓位
- * 采用分层止盈止损策略:
- * - 保护止损:价格突破BOLL中轨
- * - 跟踪止损:价格有效突破移动平均线
- * - 最终平仓:趋势反转信号(MA多头排列 + MACD金叉)
- * @param currentPrice 当前价格
- * @param volume 成交量列表
- * @param fiveMinPrices 5分钟价格数据
- * @param oneHourPrices 1小时价格数据
- * @param fourHourPrices 4小时价格数据
- * @return 是否应该平空
- */
- private boolean shouldCloseShort(BigDecimal currentPrice, List<BigDecimal> volume,
- List<BigDecimal> fiveMinPrices,
- List<BigDecimal> oneHourPrices,
- List<BigDecimal> fourHourPrices) {
- // 保护止损:价格突破BOLL中轨(关键阻力位)
- boolean isStopLossTriggered = currentPrice.compareTo(boll.getMid()) > 0;
-
- // 跟踪止损:价格有效突破短期均线(5EMA)
- boolean isTrailingStopTriggered = currentPrice.compareTo(ma.getEma5()) > 0;
-
- // 趋势反转信号:MA多头排列 + MACD金叉
- boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 &&
- ma.getEma10().compareTo(ma.getEma20()) > 0;
- boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0;
- boolean isTrendReversed = isMaBullish && isMacdBullish;
-
- // 多周期确认(看涨)
- boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
-
- // 平空条件:保护止损触发 或 跟踪止损触发 或 (趋势反转且多周期确认)
- return isStopLossTriggered || isTrailingStopTriggered || (isTrendReversed && isMultiTimeframeConfirmed);
- }
-
- /**
- * 获取所有指标的当前状态
- * @return 指标状态字符串
- */
- public String getIndicatorStatus() {
- return String.format("MA5: %s, MA20: %s, ", ma.getEma5(), ma.getEma20()) +
- String.format("MACD-DIF: %s, MACD-DEA: %s, MACD-BAR: %s, ", macd.getDif(), macd.getDea(), macd.getMacdBar()) +
- String.format("KDJ-K: %s, KDJ-D: %s, KDJ-J: %s, ", kdj.getK(), kdj.getD(), kdj.getJ()) +
- String.format("RSI: %s, ", rsi.getRsi()) +
- String.format("BOLL-MID: %s, BOLL-UP: %s, BOLL-DN: %s, ", boll.getMid(), boll.getUpper(), boll.getLower()) +
- String.format("AdvancedMA-Bullish: %s, Bearish: %s, Percent: %s",
- advancedMA.isBullish(), advancedMA.isBearish(), advancedMA.calculatePercent());
- }
-
- /**
- * 生成区间交易信号
- * 在震荡行情下,使用BOLL通道作为区间边界,结合KDJ指标生成交易信号
- * @param currentPrice 当前价格
- * @param volume 成交量列表
- * @param hasLongPosition 是否当前持有做多仓位
- * @param hasShortPosition 是否当前持有做空仓位
- * @return 交易信号
- */
- private SignalType generateRangeTradingSignal(BigDecimal currentPrice, List<BigDecimal> volume,
- boolean hasLongPosition, boolean hasShortPosition) {
- // 区间交易策略逻辑:
- // 1. 价格触及BOLL下轨且KDJ超卖 → 买入信号
- // 2. 价格触及BOLL上轨且KDJ超买 → 卖出信号
- // 3. 价格回归BOLL中轨 → 平仓信号
-
- // 检查KDJ极端超买超卖情况
- boolean isKdjJExtremeOverbought = kdj.getJ().compareTo(new BigDecimal("100")) > 0;
- boolean isKdjJExtremeOversold = kdj.getJ().compareTo(new BigDecimal("10")) < 0;
-
- // 价格触及BOLL下轨(基础条件)
- boolean isPriceNearBollLower = currentPrice.compareTo(boll.getLower()) >= 0 &&
- currentPrice.compareTo(boll.getLower().multiply(new BigDecimal("1.01"))) <= 0;
-
- // 价格触及BOLL上轨(基础条件)
- boolean isPriceNearBollUpper = currentPrice.compareTo(boll.getUpper()) <= 0 &&
- currentPrice.compareTo(boll.getUpper().multiply(new BigDecimal("0.99"))) >= 0;
-
- // 当KDJ-J极度超买/超卖时,放宽BOLL边界要求
- if (isKdjJExtremeOverbought) {
- isPriceNearBollUpper = currentPrice.compareTo(boll.getUpper().multiply(new BigDecimal("0.985"))) >= 0;
- }
- if (isKdjJExtremeOversold) {
- isPriceNearBollLower = currentPrice.compareTo(boll.getLower().multiply(new BigDecimal("1.015"))) <= 0;
- }
-
- // 价格回归BOLL中轨附近
- boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal("0.998"))) >= 0 &&
- currentPrice.compareTo(boll.getMid().multiply(new BigDecimal("1.002"))) <= 0;
-
- // KDJ超卖(使用调整后的阈值)
- boolean isKdjOversold = kdj.getJ().compareTo(new BigDecimal(15)) < 0;
-
- // KDJ超买(使用调整后的阈值)
- boolean isKdjOverbought = kdj.getJ().compareTo(new BigDecimal(85)) > 0;
-
- // RSI超卖(<30)
- boolean isRsiOversold = rsi.getRsi().compareTo(new BigDecimal(30)) < 0;
-
- // RSI超买(>70)
- boolean isRsiOverbought = rsi.getRsi().compareTo(new BigDecimal(70)) > 0;
-
- // 成交量验证(当前成交量大于20周期均值的1.1倍)
- boolean isVolumeValid = volumeConfirm(volume) &&
- volume.get(volume.size() - 1).compareTo(calculateMA(volume, config.getVolumeMaPeriod()).multiply(new BigDecimal("1.1"))) > 0;
-
- // 开多逻辑:价格触及BOLL下轨且KDJ超卖且RSI超卖且有成交量支持
- if (isPriceNearBollLower && isKdjOversold && isRsiOversold && isVolumeValid && !hasLongPosition && !hasShortPosition) {
- log.info("区间交易:价格触及BOLL下轨({}), KDJ-J值({})超卖,RSI({})超卖,生成买入信号", boll.getLower(), kdj.getJ(), rsi.getRsi());
- return SignalType.BUY;
- }
-
- // 开空逻辑:价格触及BOLL上轨且KDJ超买且RSI超买且有成交量支持
- if (isPriceNearBollUpper && isKdjOverbought && isRsiOverbought && isVolumeValid && !hasLongPosition && !hasShortPosition) {
- log.info("区间交易:价格触及BOLL上轨({}), KDJ-J值({})超买,RSI({})超买,生成卖出信号", boll.getUpper(), kdj.getJ(), rsi.getRsi());
- return SignalType.SELL;
- }
-
- // 平多逻辑:价格回归BOLL中轨
- if (isPriceNearBollMid && hasLongPosition) {
- log.info("区间交易:价格回归BOLL中轨({}),生成平多信号", boll.getMid());
- return SignalType.CLOSE_BUY;
- }
-
- // 平空逻辑:价格回归BOLL中轨
- if (isPriceNearBollMid && hasShortPosition) {
- log.info("区间交易:价格回归BOLL中轨({}),生成平空信号", boll.getMid());
- return SignalType.CLOSE_SELL;
- }
-
- return SignalType.NONE;
- }
-
- /**
- * 计算动态杠杆倍数
- * 杠杆倍数 = 基础杠杆 * (波动率阈值/当前波动率)
- * @param high 最高价列表
- * @param low 最低价列表
- * @param close 收盘价列表
- * @return 动态杠杆倍数
- */
- public BigDecimal calculateDynamicLeverage(List<BigDecimal> high, List<BigDecimal> low, List<BigDecimal> close) {
- if (!config.isEnableDynamicLeverage()) {
- return config.getBaseLeverage();
- }
-
- // 计算当前ATR和波动率
- BigDecimal currentAtr = calculateATR(high, low, close, config.getAtrPeriod());
- BigDecimal currentVolatility = normalizeVolatility(close, currentAtr);
-
- // 计算30日ATR移动中位数作为波动率阈值
- BigDecimal volatilityThreshold = calculateVolatilityThreshold(high, low, close);
-
- // 动态计算杠杆倍数
- BigDecimal leverage = config.getBaseLeverage().multiply(volatilityThreshold).divide(currentVolatility, 2, BigDecimal.ROUND_HALF_UP);
-
- // 限制杠杆范围在1x-10x之间
- leverage = leverage.min(new BigDecimal(10)).max(BigDecimal.ONE);
-
- log.info("动态杠杆计算 - 基础杠杆: {}, 波动率阈值: {}, 当前波动率: {}, 计算杠杆: {}",
- config.getBaseLeverage(), volatilityThreshold, currentVolatility, leverage);
-
- return leverage;
- }
-
- /**
- * 计算波动率阈值(30日ATR移动中位数)
- * @param high 最高价列表
- * @param low 最低价列表
- * @param close 收盘价列表
- * @return 波动率阈值
- */
- private BigDecimal calculateVolatilityThreshold(List<BigDecimal> high, List<BigDecimal> low, List<BigDecimal> close) {
- if (high == null || low == null || close == null || close.size() < config.getVolatilityThresholdPeriod()) {
- return new BigDecimal(5); // 默认阈值
- }
-
- List<BigDecimal> volatilityList = new ArrayList<>();
- for (int i = close.size() - config.getVolatilityThresholdPeriod(); i < close.size(); i++) {
- List<BigDecimal> recentHigh = high.subList(Math.max(0, i - config.getAtrPeriod()), i + 1);
- List<BigDecimal> recentLow = low.subList(Math.max(0, i - config.getAtrPeriod()), i + 1);
- List<BigDecimal> recentClose = close.subList(Math.max(0, i - config.getAtrPeriod()), i + 1);
-
- BigDecimal atr = calculateATR(recentHigh, recentLow, recentClose, config.getAtrPeriod());
- BigDecimal volatility = normalizeVolatility(recentClose, atr);
- volatilityList.add(volatility);
- }
-
- // 计算中位数
- volatilityList.sort(BigDecimal::compareTo);
- int midIndex = volatilityList.size() / 2;
- return volatilityList.get(midIndex);
- }
-
- /**
- * 三段式止盈策略
- * 第一目标:BOLL上轨(30%仓位)
- * 第二目标:斐波那契161.8%(50%仓位)
- * 第三目标:趋势线破位(20%仓位)
- * @param entryPrice 入场价格
- * @param currentPrice 当前价格
- * @param direction 交易方向
- * @param positionSize 当前仓位大小
- * @return 止盈信号和应该平仓的仓位比例
- */
- public ProfitTakingResult calculateThreeStepProfitTaking(BigDecimal entryPrice, BigDecimal currentPrice,
- Direction direction, BigDecimal positionSize) {
- if (!config.isEnableThreeStepProfitTaking()) {
- return new ProfitTakingResult(SignalType.NONE, BigDecimal.ZERO);
- }
-
- // 计算三个止盈目标
- BigDecimal firstTarget = calculateFirstProfitTarget(entryPrice, currentPrice, direction);
- BigDecimal secondTarget = calculateSecondProfitTarget(entryPrice, direction);
- BigDecimal thirdTarget = calculateThirdProfitTarget(currentPrice, direction);
-
- // 判断当前价格是否达到目标
- if (direction == Direction.LONG) {
- if (currentPrice.compareTo(thirdTarget) >= 0) {
- // 达到第三目标,平全部仓位
- return new ProfitTakingResult(SignalType.CLOSE_BUY, positionSize);
- } else if (currentPrice.compareTo(secondTarget) >= 0) {
- // 达到第二目标,平50%仓位
- return new ProfitTakingResult(SignalType.CLOSE_BUY, positionSize.multiply(new BigDecimal("0.5")));
- } else if (currentPrice.compareTo(firstTarget) >= 0) {
- // 达到第一目标,平30%仓位
- return new ProfitTakingResult(SignalType.CLOSE_BUY, positionSize.multiply(new BigDecimal("0.3")));
- }
- } else if (direction == Direction.SHORT) {
- if (currentPrice.compareTo(thirdTarget) <= 0) {
- // 达到第三目标,平全部仓位
- return new ProfitTakingResult(SignalType.CLOSE_SELL, positionSize);
- } else if (currentPrice.compareTo(secondTarget) <= 0) {
- // 达到第二目标,平50%仓位
- return new ProfitTakingResult(SignalType.CLOSE_SELL, positionSize.multiply(new BigDecimal("0.5")));
- } else if (currentPrice.compareTo(firstTarget) <= 0) {
- // 达到第一目标,平30%仓位
- return new ProfitTakingResult(SignalType.CLOSE_SELL, positionSize.multiply(new BigDecimal("0.3")));
- }
- }
-
- return new ProfitTakingResult(SignalType.NONE, BigDecimal.ZERO);
- }
-
- /**
- * 计算第一止盈目标:BOLL上轨
- */
- private BigDecimal calculateFirstProfitTarget(BigDecimal entryPrice, BigDecimal currentPrice, Direction direction) {
- return direction == Direction.LONG ? boll.getUpper() : boll.getLower();
- }
-
- /**
- * 计算第二止盈目标:斐波那契161.8%
- */
- private BigDecimal calculateSecondProfitTarget(BigDecimal entryPrice, Direction direction) {
- BigDecimal fibonacciRatio = new BigDecimal("1.618");
- if (direction == Direction.LONG) {
- return entryPrice.multiply(BigDecimal.ONE.add(fibonacciRatio.divide(new BigDecimal(100))));
- } else {
- return entryPrice.multiply(BigDecimal.ONE.subtract(fibonacciRatio.divide(new BigDecimal(100))));
- }
- }
-
- /**
- * 计算第三止盈目标:简单趋势线破位(这里简化为MA5下穿MA20)
- */
- private BigDecimal calculateThirdProfitTarget(BigDecimal currentPrice, Direction direction) {
- // 这里使用简化的趋势线破位判断
- // 实际应用中可以使用更复杂的趋势线计算
- return direction == Direction.LONG ? ma.getEma20() : ma.getEma20();
- }
-
-
-
- /**
- * 黑天鹅事件过滤
- * 规避重大事件前后30分钟、链上大额转账、异常资金费率
- * @param fundingRate 当前资金费率
- * @param hasLargeTransfer 是否有大额转账
- * @param hasUpcomingEvent 是否有即将到来的重大事件
- * @return 是否应该规避交易
- */
- public boolean blackSwanFilter(BigDecimal fundingRate, boolean hasLargeTransfer, boolean hasUpcomingEvent) {
- if (!config.isEnableBlackSwanFilter()) {
- return false;
- }
-
- // 资金费率绝对值大于0.2%
- boolean isAbnormalFundingRate = fundingRate != null &&
- fundingRate.abs().compareTo(new BigDecimal("0.002")) > 0;
-
- // 大额转账监控(这里简化为外部传入)
- // 重大事件监控(这里简化为外部传入)
-
- boolean shouldAvoid = isAbnormalFundingRate || hasLargeTransfer || hasUpcomingEvent;
-
- if (shouldAvoid) {
- log.info("黑天鹅事件过滤触发 - 资金费率异常: {}, 大额转账: {}, 即将发生重大事件: {}",
- isAbnormalFundingRate, hasLargeTransfer, hasUpcomingEvent);
- }
-
- return shouldAvoid;
- }
-
- /**
- * 止盈结果类
- */
- public static class ProfitTakingResult {
- private SignalType signal;
- private BigDecimal closePositionSize;
-
- public ProfitTakingResult(SignalType signal, BigDecimal closePositionSize) {
- this.signal = signal;
- this.closePositionSize = closePositionSize;
- }
-
- public SignalType getSignal() {
- return signal;
- }
-
- public BigDecimal getClosePositionSize() {
- return closePositionSize;
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/EMACalculator.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/EMACalculator.java
deleted file mode 100644
index 019b1a1..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/EMACalculator.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * 指数移动平均线(EMA)计算器
- * <p>
- * EMA(Exponential Moving Average)是一种加权移动平均线,对近期价格赋予更高权重,
- * 对远期价格赋予较低权重,能够更敏感地反映价格变化趋势。
- * 本计算器提供了EMA的多种计算方式,支持使用SMA作为初始值或使用第一个价格作为初始值。
- */
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 指数移动平均线(EMA)计算器
- *
- * <p>计算公式:EMA(today) = Price(today) * k + EMA(yesterday) * (1 - k)</p>
- * <p>其中:k = 2 / (period + 1),period为EMA的周期</p>
- */
-public class EMACalculator {
- /**
- * 计算价格序列的指数移动平均线(EMA)
- *
- * @param prices 价格序列,使用BigDecimal确保计算精度
- * @param period EMA计算周期
- * @param initialSMA 是否使用SMA(简单移动平均线)作为初始值
- * @return 计算得到的EMA序列,与输入价格序列一一对应
- * @throws IllegalArgumentException 当输入参数无效时抛出异常
- */
- public static List<BigDecimal> calculateEMA(List<BigDecimal> prices, int period, boolean initialSMA) {
- if (prices == null || prices.isEmpty() || period <= 0) {
- throw new IllegalArgumentException("Invalid input parameters.");
- }
- if (initialSMA && prices.size() < period) {
- throw new IllegalArgumentException("Prices list too short for initial SMA.");
- }
-
- // 计算权重因子k = 2 / (period + 1)
- BigDecimal alpha = BigDecimal.valueOf(2.0).divide(BigDecimal.valueOf(period + 1), 10, RoundingMode.HALF_UP);
- List<BigDecimal> ema = new ArrayList<>();
-
- if (initialSMA) {
- // 使用SMA作为初始EMA值(前period个价格的平均值)
- BigDecimal sum = BigDecimal.ZERO;
- for (int i = 0; i < period; i++) {
- sum = sum.add(prices.get(i));
- }
- BigDecimal sma = sum.divide(BigDecimal.valueOf(period), 10, RoundingMode.HALF_UP);
- ema.add(sma);
-
- // 从第period+1个数据点开始计算后续EMA值
- for (int i = period; i < prices.size(); i++) {
- BigDecimal price = prices.get(i);
- BigDecimal prevEMA = ema.get(ema.size() - 1);
- // EMA计算公式:Price(today) * alpha + EMA(yesterday) * (1 - alpha)
- BigDecimal emaToday = price.multiply(alpha)
- .add(prevEMA.multiply(BigDecimal.ONE.subtract(alpha)))
- .setScale(10, RoundingMode.HALF_UP);
- ema.add(emaToday);
- }
- } else {
- // 使用第一个价格作为初始EMA值,并从第二个数据点开始计算
- ema.add(prices.get(0));
- for (int i = 1; i < prices.size(); i++) {
- BigDecimal price = prices.get(i);
- BigDecimal prevEMA = ema.get(ema.size() - 1);
- // EMA计算公式:Price(today) * alpha + EMA(yesterday) * (1 - alpha)
- BigDecimal emaToday = price.multiply(alpha)
- .add(prevEMA.multiply(BigDecimal.ONE.subtract(alpha)))
- .setScale(10, RoundingMode.HALF_UP);
- ema.add(emaToday);
- }
- }
-
- return ema;
- }
-
- /**
- * 计算价格序列的指数移动平均线(EMA),默认使用SMA作为初始值
- *
- * @param prices 价格序列
- * @param period EMA计算周期
- * @return 计算得到的EMA序列
- */
- public static List<BigDecimal> calculateEMA(List<BigDecimal> prices, int period) {
- return calculateEMA(prices, period, true);
- }
-
- /**
- * 计算单个EMA值(递归计算方式)
- *
- * @param currentPrice 当前价格
- * @param prevEMA 前一个EMA值
- * @param period EMA周期
- * @return 当前EMA值
- */
- public static BigDecimal calculateSingleEMA(BigDecimal currentPrice, BigDecimal prevEMA, int period) {
- // 计算权重因子alpha = 2 / (period + 1)
- BigDecimal alpha = BigDecimal.valueOf(2.0).divide(BigDecimal.valueOf(period + 1), 10, RoundingMode.HALF_UP);
-
- // EMA(today) = Price(today) * alpha + EMA(yesterday) * (1 - alpha)
- return currentPrice.multiply(alpha)
- .add(prevEMA.multiply(BigDecimal.ONE.subtract(alpha)))
- .setScale(10, RoundingMode.HALF_UP);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/IndicatorUtils.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/IndicatorUtils.java
deleted file mode 100644
index a3cbec7..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/IndicatorUtils.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * 指标计算工具类
- * 封装MACD策略中常用的通用功能,如高低点查找等
- */
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * 指标计算工具类,提供MACD策略中常用的通用功能
- */
-public class IndicatorUtils {
-
- /**
- * 找到最近的价格高点索引
- *
- * @param prices 价格列表
- * @param startIdx 起始索引
- * @return 最近的价格高点索引
- */
- public static int findRecentHighIndex(List<BigDecimal> prices, int startIdx) {
- if (prices == null || startIdx < 0 || startIdx >= prices.size()) {
- return -1;
- }
-
- int highIdx = startIdx;
- BigDecimal highPrice = prices.get(startIdx);
-
- for (int i = startIdx + 1; i < prices.size(); i++) {
- BigDecimal currentPrice = prices.get(i);
- if (currentPrice.compareTo(highPrice) > 0) {
- highPrice = currentPrice;
- highIdx = i;
- }
- }
-
- return highIdx;
- }
-
- /**
- * 找到最近的价格低点索引
- *
- * @param prices 价格列表
- * @param startIdx 起始索引
- * @return 最近的价格低点索引
- */
- public static int findRecentLowIndex(List<BigDecimal> prices, int startIdx) {
- if (prices == null || startIdx < 0 || startIdx >= prices.size()) {
- return -1;
- }
-
- int lowIdx = startIdx;
- BigDecimal lowPrice = prices.get(startIdx);
-
- for (int i = startIdx + 1; i < prices.size(); i++) {
- BigDecimal currentPrice = prices.get(i);
- if (currentPrice.compareTo(lowPrice) < 0) {
- lowPrice = currentPrice;
- lowIdx = i;
- }
- }
-
- return lowIdx;
- }
-
- /**
- * 找到最近价格高点之前的价格高点索引
- *
- * @param prices 价格列表
- * @param startIdx 起始索引
- * @param recentHighIdx 最近的价格高点索引
- * @return 之前的价格高点索引
- */
- public static int findPreviousHighIndex(List<BigDecimal> prices, int startIdx, int recentHighIdx) {
- if (prices == null || startIdx < 0 || recentHighIdx <= startIdx || recentHighIdx >= prices.size()) {
- return -1;
- }
-
- int highIdx = startIdx;
- BigDecimal highPrice = prices.get(startIdx);
-
- for (int i = startIdx + 1; i < recentHighIdx; i++) {
- BigDecimal currentPrice = prices.get(i);
- if (currentPrice.compareTo(highPrice) > 0) {
- highPrice = currentPrice;
- highIdx = i;
- }
- }
-
- return highIdx;
- }
-
- /**
- * 找到最近价格低点之前的价格低点索引
- *
- * @param prices 价格列表
- * @param startIdx 起始索引
- * @param recentLowIdx 最近的价格低点索引
- * @return 之前的价格低点索引
- */
- public static int findPreviousLowIndex(List<BigDecimal> prices, int startIdx, int recentLowIdx) {
- if (prices == null || startIdx < 0 || recentLowIdx <= startIdx || recentLowIdx >= prices.size()) {
- return -1;
- }
-
- int lowIdx = startIdx;
- BigDecimal lowPrice = prices.get(startIdx);
-
- for (int i = startIdx + 1; i < recentLowIdx; i++) {
- BigDecimal currentPrice = prices.get(i);
- if (currentPrice.compareTo(lowPrice) < 0) {
- lowPrice = currentPrice;
- lowIdx = i;
- }
- }
-
- return lowIdx;
- }
-
- /**
- * 寻找最近的价格高点(带有回调确认)
- *
- * @param prices 价格列表
- * @param startIndex 起始索引
- * @param endIndex 结束索引
- * @return 符合条件的价格高点索引,未找到则返回-1
- */
- public static int findRecentHighWithRetrace(List<BigDecimal> prices, int startIndex, int endIndex) {
- if (prices == null || startIndex < 0 || endIndex >= prices.size() || startIndex >= endIndex) {
- return -1;
- }
-
- int highIndex = -1;
- BigDecimal highPrice = BigDecimal.ZERO;
-
- // 从右向左搜索,找到第一个有效高点
- for (int i = endIndex; i >= startIndex; i--) {
- if (prices.get(i).compareTo(highPrice) > 0) {
- highPrice = prices.get(i);
- highIndex = i;
- }
-
- // 检查高点后是否有回调
- if (highIndex != -1 && i < endIndex) {
- if (prices.get(i + 1).compareTo(highPrice) < 0) {
- return highIndex; // 找到确认回调的高点
- }
- }
- }
-
- return highIndex;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDCalculator.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDCalculator.java
deleted file mode 100644
index 5538216..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDCalculator.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * MACD(Moving Average Convergence Divergence)指标计算器
- * <p>
- * MACD指标由三部分组成:
- * 1. DIF(Difference):短期EMA与长期EMA的差值
- * 2. DEA(Signal Line):DIF的指数移动平均线,作为MACD的信号线
- * 3. MACD柱状图(Histogram):DIF与DEA的差值,反映市场动量
- * <p>
- * 默认参数:短期周期=12,长期周期=26,信号周期=9
- */
-public class MACDCalculator {
-
- /**
- * 计算MACD指标
- *
- * @param closePrices 收盘价列表(使用BigDecimal确保计算精度)
- * @param fastlen 短期EMA周期(通常为12)
- * @param slowlen 长期EMA周期(通常为26)
- * @param siglen DEA的周期(通常为9)
- * @return 包含MACD各部分数据的PriceData列表
- * @throws IllegalArgumentException 如果数据点不足或参数无效
- */
- public static MACDResult calculateMACD(List<BigDecimal> closePrices, int fastlen, int slowlen, int siglen) {
- // 参数校验:确保数据点足够
- if (closePrices == null || closePrices.isEmpty()) {
- throw new IllegalArgumentException("Close prices list cannot be null or empty.");
- }
- if (fastlen <= 0 || slowlen <= 0 || siglen <= 0) {
- throw new IllegalArgumentException("All periods must be positive integers.");
- }
- if (fastlen >= slowlen) {
- throw new IllegalArgumentException("Fast period must be less than slow period.");
- }
- if (closePrices.size() < Math.max(fastlen, slowlen)) {
- throw new IllegalArgumentException("Insufficient data points for the specified periods.");
- }
-
- // 反转数据,确保从旧到新处理(因为用户提供的数据是从新到旧)
- List<BigDecimal> prices = new ArrayList<>(closePrices);
- Collections.reverse(prices);
-
- // 1. 计算快速EMA和慢速EMA,使用SMA作为初始值
- // 当initialSMA=true时,EMA列表长度为prices.size() - period + 1
- List<BigDecimal> fastEma = EMACalculator.calculateEMA(prices, fastlen, true);
- List<BigDecimal> slowEma = EMACalculator.calculateEMA(prices, slowlen, true);
-
- // 2. 计算MACD线(快速EMA减去慢速EMA)
- List<BigDecimal> macdLine = new ArrayList<>();
- // EMA列表的起始索引与价格列表的对应关系
- int slowEmaStartIdx = slowlen - 1; // slowEma中第一个有效值对应的价格索引
- int fastEmaStartIdx = fastlen - 1; // fastEma中第一个有效值对应的价格索引
-
- for (int i = 0; i < prices.size(); i++) {
- if (i < slowEmaStartIdx) {
- // 在慢速EMA开始有效之前,MACD线值为0
- macdLine.add(BigDecimal.ZERO);
- } else {
- // MACD线 = 快速EMA - 慢速EMA
- // 需要将价格索引转换为EMA列表索引
- int slowEmaIdx = i - slowEmaStartIdx;
- int fastEmaIdx = i - fastEmaStartIdx;
- BigDecimal macdValue = fastEma.get(fastEmaIdx).subtract(slowEma.get(slowEmaIdx));
- macdLine.add(macdValue);
- }
- }
-
- // 3. 计算信号线(MACD线的siglen周期EMA),使用SMA作为初始值
- List<BigDecimal> signalLine = EMACalculator.calculateEMA(macdLine, siglen, true);
-
- // 4. 计算柱状图(MACD线与信号线的差值)
- List<BigDecimal> histogram = new ArrayList<>();
- int signalLineStartIdx = siglen - 1; // signalLine中第一个有效值对应的macdLine索引
-
- for (int i = 0; i < macdLine.size(); i++) {
- if (i < slowEmaStartIdx + signalLineStartIdx) {
- // 在信号线开始有效之前,柱状图值为0
- histogram.add(BigDecimal.ZERO);
- } else {
- // 将macdLine索引转换为signalLine索引
- int signalLineIdx = i - signalLineStartIdx;
- // 柱状图 = (MACD线 - 信号线) * 2(放大信号)
- BigDecimal histValue = macdLine.get(i).subtract(signalLine.get(signalLineIdx)).multiply(new BigDecimal("2"));
- histogram.add(histValue);
- }
- }
-
- // 5. 构建结果数据
- List<PriceData> result = new ArrayList<>();
- int startIndex = slowEmaStartIdx + signalLineStartIdx; // 从信号线开始有效的位置开始
-
- for (int i = startIndex; i < prices.size(); i++) {
- PriceData data = new PriceData(prices.get(i));
-
- // 设置EMA值(需要转换索引)
- int fastEmaIdx = i - fastEmaStartIdx;
- int slowEmaIdx = i - slowEmaStartIdx;
- data.setEmaShort(fastEma.get(fastEmaIdx));
- data.setEmaLong(slowEma.get(slowEmaIdx));
-
- // 设置MACD指标值
- data.setDif(macdLine.get(i));
- data.setDea(signalLine.get(i - signalLineStartIdx));
- data.setMacdHist(histogram.get(i));
-
- result.add(data);
- }
-
- // 反转结果列表,恢复为从新到旧的顺序
- Collections.reverse(result);
-
- return new MACDResult(result, startIndex);
- }
-
- /**
- * 使用默认参数计算MACD指标
- * <p>
- * 默认参数:短期周期=12,长期周期=26,信号周期=9
- *
- * @param closePrices 收盘价列表
- * @return 包含MACD各部分数据的PriceData列表
- */
- public static MACDResult calculateMACD(List<BigDecimal> closePrices) {
- // 默认参数:快速周期12,慢速周期26,信号周期9
- return calculateMACD(closePrices, 12, 26, 9);
- }
-
- /**
- * 判断是否出现顶背离
- * <p>
- * 顶背离:价格创新高,但DIF未创新高,且与价格走势背离
- * 增强空头信号可靠性
- *
- * @param closePrices 原始收盘价列表
- * @param macdResult MACD计算结果
- * @return 是否出现顶背离
- */
- public static boolean isTopDivergence(List<BigDecimal> closePrices, MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- int startIdx = macdResult.getStartIndex();
-
- // 确保有足够的数据点进行判断(至少需要2个高点)
- if (macdData.size() < 10) {
- return false;
- }
-
- // 反转原始价格列表,确保从旧到新处理
- List<BigDecimal> prices = new ArrayList<>(closePrices);
- Collections.reverse(prices);
-
- // 找到最近的价格高点和对应的DIF值
- int recentPriceHighIdx = IndicatorUtils.findRecentHighIndex(prices, startIdx);
- if (recentPriceHighIdx < startIdx + 2 || recentPriceHighIdx == -1) {
- return false;
- }
-
- // 找到之前的价格高点和对应的DIF值
- int previousPriceHighIdx = IndicatorUtils.findPreviousHighIndex(prices, startIdx, recentPriceHighIdx);
- if (previousPriceHighIdx < startIdx || previousPriceHighIdx == -1) {
- return false;
- }
-
- // 获取对应位置的DIF值
- int recentDifIdx = recentPriceHighIdx - startIdx;
- int previousDifIdx = previousPriceHighIdx - startIdx;
-
- // 边界检查
- if (recentDifIdx >= macdData.size() || previousDifIdx >= macdData.size()) {
- return false;
- }
-
- BigDecimal recentPrice = prices.get(recentPriceHighIdx);
- BigDecimal previousPrice = prices.get(previousPriceHighIdx);
- BigDecimal recentDif = macdData.get(recentDifIdx).getDif();
- BigDecimal previousDif = macdData.get(previousDifIdx).getDif();
-
- // 顶背离条件:价格创新高,但DIF未创新高
- return recentPrice.compareTo(previousPrice) > 0 &&
- recentDif.compareTo(previousDif) < 0;
- }
-
- /**
- * 判断是否出现底背离
- * <p>
- * 底背离:价格创新低,但DIF未创新低,且与价格走势背离
- * 增强多头信号可靠性
- *
- * @param closePrices 原始收盘价列表
- * @param macdResult MACD计算结果
- * @return 是否出现底背离
- */
- public static boolean isBottomDivergence(List<BigDecimal> closePrices, MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- int startIdx = macdResult.getStartIndex();
-
- // 确保有足够的数据点进行判断(至少需要2个低点)
- if (macdData.size() < 10) {
- return false;
- }
-
- // 反转原始价格列表,确保从旧到新处理
- List<BigDecimal> prices = new ArrayList<>(closePrices);
- Collections.reverse(prices);
-
- // 找到最近的价格低点和对应的DIF值
- int recentPriceLowIdx = IndicatorUtils.findRecentLowIndex(prices, startIdx);
- if (recentPriceLowIdx < startIdx + 2 || recentPriceLowIdx == -1) {
- return false;
- }
-
- // 找到之前的价格低点和对应的DIF值
- int previousPriceLowIdx = IndicatorUtils.findPreviousLowIndex(prices, startIdx, recentPriceLowIdx);
- if (previousPriceLowIdx < startIdx || previousPriceLowIdx == -1) {
- return false;
- }
-
- // 获取对应位置的DIF值
- int recentDifIdx = recentPriceLowIdx - startIdx;
- int previousDifIdx = previousPriceLowIdx - startIdx;
-
- // 边界检查
- if (recentDifIdx >= macdData.size() || previousDifIdx >= macdData.size()) {
- return false;
- }
-
- BigDecimal recentPrice = prices.get(recentPriceLowIdx);
- BigDecimal previousPrice = prices.get(previousPriceLowIdx);
- BigDecimal recentDif = macdData.get(recentDifIdx).getDif();
- BigDecimal previousDif = macdData.get(previousDifIdx).getDif();
-
- // 底背离条件:价格创新低,但DIF未创新低
- return recentPrice.compareTo(previousPrice) < 0 &&
- recentDif.compareTo(previousDif) > 0;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDResult.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDResult.java
deleted file mode 100644
index 0ab00ae..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDResult.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * MACD计算结果类
- * <p>
- * 用于封装MACD指标计算的结果数据,包括完整的MACD数据序列和数据的起始索引信息,
- * 方便策略模块获取和使用MACD计算结果。
- */
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import java.util.List;
-
-/**
- * MACD计算结果封装类
- */
-public class MACDResult {
- /** MACD完整数据序列,包含每个价格点对应的DIF、DEA和MACD柱状图值 */
- private List<PriceData> macdData;
-
- /** 在原始价格序列中的起始索引,表示MACD数据的计算起点 */
- private int startIndex;
-
- /**
- * 构造函数,创建MACD计算结果对象
- *
- * @param result 计算得到的MACD数据序列
- * @param startIdx 数据在原始价格序列中的起始索引
- */
- public MACDResult(List<PriceData> result, int startIdx) {
- this.macdData = result;
- this.startIndex = startIdx;
- }
-
- /**
- * 获取MACD数据序列
- * @return MACD数据序列
- */
- public List<PriceData> getMacdData() {
- return macdData;
- }
-
- /**
- * 获取起始索引
- * @return 起始索引值
- */
- public int getStartIndex() {
- return startIndex;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdEmaStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdEmaStrategy.java
deleted file mode 100644
index 8dab3cb..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdEmaStrategy.java
+++ /dev/null
@@ -1,463 +0,0 @@
-/**
- * MACD和MA组合交易策略实现类
- * 基于多时间粒度K线数据生成交易信号并确定持仓方向
- *
- * 该策略综合考虑了EMA指标、MACD指标、价格突破信号和波动率因素,
- * 形成了一套完整的开仓、平仓和持仓管理机制。
- * 支持1分钟(K线)和1分钟(K线)级别的数据输入,数据顺序要求从新到旧排列。
- */
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * MACD和MA组合交易策略实现
- * <p>
- * 该策略利用EMA交叉、MACD指标、价格突破信号和波动率过滤,
- * 为多时间粒度K线级别交易提供综合决策支持。
- * <p>
- * 数据输入要求:
- * - historicalPrices1M:1分钟K线收盘价列表,顺序从新到旧
- * - historicalPrices1D:日线K线收盘价列表,顺序从新到旧
- */
-@Slf4j
-public class MacdEmaStrategy {
-
- /** 操作类型枚举 */
- public enum OperationType {
- /** 开仓 */
- open,
- /** 平仓 */
- close
- }
-
- /** 持仓状态枚举 */
- public enum PositionType {
- /** 多头开仓 */
- LONG_BUY,
- /** 多头平仓 */
- LONG_SELL,
- /** 空头开仓 */
- SHORT_SELL,
- /** 空头平仓 */
- SHORT_BUY,
- /** 空仓 */
- NONE
- }
-
- /** 交易指令类,封装side和posSide的组合 */
- public static class TradingOrder {
- private String side; // buy或sell
- private String posSide; // long或short
-
- public TradingOrder(String side, String posSide) {
- this.side = side;
- this.posSide = posSide;
- }
-
- public String getSide() {
- return side;
- }
-
- public String getPosSide() {
- return posSide;
- }
-
- @Override
- public String toString() {
- return String.format("TradingOrder{side='%s', posSide='%s'}", side, posSide);
- }
- }
-
- // 策略参数
- private int shortPeriod; // 短期EMA周期
- private int longPeriod; // 长期EMA周期
- private int signalPeriod; // MACD信号线周期
- private int volatilityPeriod; // 波动率计算周期
- private int trendPeriod = 200; // 趋势过滤EMA周期(200日)
- private BigDecimal stopLossRatio; // 止损比例
- private BigDecimal takeProfitRatio; // 止盈比例
-
- /**
- * 默认构造函数,使用标准MACD参数
- * 短期周期=12, 长期周期=26, 信号线周期=9, 波动率周期=20
- * 止损比例=1%, 止盈比例=2%
- */
- public MacdEmaStrategy() {
- this(12, 26, 9, 20, new BigDecimal("0.01"), new BigDecimal("0.02"));
- }
-
- /**
- * 自定义参数构造函数,使用默认趋势周期200
- *
- * @param shortPeriod 短期EMA周期
- * @param longPeriod 长期EMA周期
- * @param signalPeriod MACD信号线周期
- * @param volatilityPeriod 波动率计算周期
- * @param stopLossRatio 止损比例
- * @param takeProfitRatio 止盈比例
- */
- public MacdEmaStrategy(int shortPeriod, int longPeriod, int signalPeriod, int volatilityPeriod,
- BigDecimal stopLossRatio, BigDecimal takeProfitRatio) {
- this(shortPeriod, longPeriod, signalPeriod, volatilityPeriod, 200, stopLossRatio, takeProfitRatio);
- }
-
- /**
- * 自定义参数构造函数
- *
- * @param shortPeriod 短期EMA周期
- * @param longPeriod 长期EMA周期
- * @param signalPeriod MACD信号线周期
- * @param volatilityPeriod 波动率计算周期
- * @param trendPeriod 趋势过滤EMA周期(200日)
- * @param stopLossRatio 止损比例
- * @param takeProfitRatio 止盈比例
- */
- public MacdEmaStrategy(int shortPeriod, int longPeriod, int signalPeriod, int volatilityPeriod, int trendPeriod,
- BigDecimal stopLossRatio, BigDecimal takeProfitRatio) {
- this.shortPeriod = shortPeriod;
- this.longPeriod = longPeriod;
- this.signalPeriod = signalPeriod;
- this.volatilityPeriod = volatilityPeriod;
- this.trendPeriod = trendPeriod;
- this.stopLossRatio = stopLossRatio;
- this.takeProfitRatio = takeProfitRatio;
- }
-
- // 主流程方法
-
- /**
- * 分析历史价格数据并生成交易指令
- *
- * @param historicalPrices 历史价格序列(1分钟K线收盘价),顺序从新到旧
- * @param operation 操作类型(open/close)
- * @return 交易指令(包含side和posSide),如果没有交易信号则返回null
- */
- public TradingOrder generateTradingOrder(List<BigDecimal> historicalPrices, String operation) {
- PositionType signal = null;
-
- if (OperationType.open.name().equals(operation)) {
- signal = analyzeOpen(historicalPrices);
- } else if (OperationType.close.name().equals(operation)) {
- signal = analyzeClose(historicalPrices);
- }
-
- // 根据信号生成交易指令
- return convertSignalToTradingOrder(signal);
- }
-
- /**
- * 分析最新价格数据并生成开仓信号
- *
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @return 生成的交易信号(LONG_BUY、SHORT_SELL或NONE)
- */
- public PositionType analyzeOpen(List<BigDecimal> closePrices) {
- // 数据检查:确保有足够的数据点进行计算(需要足够数据计算200日EMA)
- if (closePrices == null || closePrices.size() < Math.max(34, trendPeriod)) {
- return PositionType.NONE; // 数据不足,无法生成信号
- }
-
- // 计算MACD指标
- MACDResult macdResult = MACDCalculator.calculateMACD(
- closePrices, shortPeriod, longPeriod, signalPeriod);
- log.info("MACD计算结果:{}", macdResult.getMacdData().get(0));
-
- // 多头开仓条件检查
- if (isLongEntryCondition(macdResult, closePrices)) {
- log.info("多头开仓信号,价格:{}", closePrices.get(0));
- return PositionType.LONG_BUY;
- }
-
- // 空头开仓条件检查
- if (isShortEntryCondition(macdResult, closePrices)) {
- log.info("空头开仓信号,价格:{}", closePrices.get(0));
- return PositionType.SHORT_SELL;
- }
-
- // 无信号
- return PositionType.NONE;
- }
-
- /**
- * 分析最新价格数据并生成平仓信号
- *
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @return 生成的交易信号(LONG_SELL、SHORT_BUY或NONE)
- */
- public PositionType analyzeClose(List<BigDecimal> closePrices) {
- // 数据检查:确保有足够的数据点进行计算
- if (closePrices == null || closePrices.size() < Math.max(34, trendPeriod)) {
- return PositionType.NONE; // 数据不足,无法生成信号
- }
-
- // 计算MACD指标
- MACDResult macdResult = MACDCalculator.calculateMACD(
- closePrices, shortPeriod, longPeriod, signalPeriod);
-
- // 最新收盘价
- BigDecimal latestPrice = closePrices.get(0);
-
- if (isLongExitCondition(macdResult, latestPrice)) {
- log.info("多头平仓信号,价格:{}", latestPrice);
- return PositionType.LONG_SELL;
- }
-
- if (isShortExitCondition(macdResult, latestPrice)) {
- log.info("空头平仓信号,价格:{}", latestPrice);
- return PositionType.SHORT_BUY;
- }
-
- // 无信号
- return PositionType.NONE;
- }
-
- // 信号转换方法
-
- /**
- * 将持仓信号转换为交易指令
- *
- * @param signal 持仓信号
- * @return 交易指令,无信号则返回null
- */
- private TradingOrder convertSignalToTradingOrder(PositionType signal) {
- if (signal == null) {
- return null;
- }
-
- switch (signal) {
- case LONG_BUY:
- // 开多:买入开多(side 填写 buy; posSide 填写 long )
- return new TradingOrder("buy", "long");
- case LONG_SELL:
- // 平多:卖出平多(side 填写 sell; posSide 填写 long )
- return new TradingOrder("sell", "long");
- case SHORT_SELL:
- // 开空:卖出开空(side 填写 sell; posSide 填写 short )
- return new TradingOrder("sell", "short");
- case SHORT_BUY:
- // 平空:买入平空(side 填写 buy; posSide 填写 short )
- return new TradingOrder("buy", "short");
- default:
- // 无信号
- return null;
- }
- }
-
- // 开仓条件检查方法
-
- /**
- * 多头开仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @return 是否满足多头开仓条件
- */
- private boolean isLongEntryCondition(MACDResult macdResult, List<BigDecimal> closePrices) {
- // 1. 计算200日EMA(趋势过滤)
- // 复制并反转日线数据,确保从旧到新计算EMA
- List<BigDecimal> reversed1DPrices = new ArrayList<>(closePrices);
- Collections.reverse(reversed1DPrices);
- List<BigDecimal> trendEma = EMACalculator.calculateEMA(reversed1DPrices, trendPeriod, true);
- BigDecimal latestTrendEma = trendEma.get(trendEma.size() - 1);
- BigDecimal latestPrice = closePrices.get(0);
-
- // 2. 价格必须位于200日EMA上方(多头趋势确认)
- boolean isAboveTrend = latestPrice.compareTo(latestTrendEma) > 0;
-
- // 3. MACD金叉检查
- boolean isGoldenCross = isGoldenCross(macdResult);
-
- // 4. MACD柱状线由负转正(动量转变)
- boolean isMacdHistTurningPositive = isMacdHistTurningPositive(macdResult);
-
- // 5. 底背离检查(增强多头信号可靠性)
- boolean isBottomDivergence = MACDCalculator.isBottomDivergence(closePrices, macdResult);
-
- log.info("多头信号检查, 200日EMA价格{}位于上方: {}, 金叉: {}, MACD柱状线由负转正: {}, 底背离: {}",
- latestTrendEma,isAboveTrend, isGoldenCross, isMacdHistTurningPositive, isBottomDivergence);
-
- // 多头开仓条件:柱状线转强 + 金叉 + (趋势向上或底背离)
- return isMacdHistTurningPositive && isGoldenCross && ( isAboveTrend|| isBottomDivergence);
- }
-
- /**
- * 空头开仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @return 是否满足空头开仓条件
- */
- private boolean isShortEntryCondition(MACDResult macdResult, List<BigDecimal> closePrices) {
- // 1. 计算200日EMA(趋势过滤)
- // 复制并反转日线数据,确保从旧到新计算EMA
- List<BigDecimal> reversed1DPrices = new ArrayList<>(closePrices);
- Collections.reverse(reversed1DPrices);
- List<BigDecimal> trendEma = EMACalculator.calculateEMA(reversed1DPrices, trendPeriod, true);
- BigDecimal latestTrendEma = trendEma.get(trendEma.size() - 1);
- BigDecimal latestPrice = closePrices.get(0);
-
- // 2. 价格必须位于200日EMA下方(空头趋势确认)
- boolean isBelowTrend = latestPrice.compareTo(latestTrendEma) < 0;
-
- // 3. MACD死叉检查
- boolean isDeathCross = isDeathCross(macdResult);
-
- // 4. MACD柱状线由正转负(动量转变)
- boolean isMacdHistTurningNegative = isMacdHistTurningNegative(macdResult);
-
- // 5. 顶背离检查(增强空头信号可靠性)
- boolean isTopDivergence = MACDCalculator.isTopDivergence(closePrices, macdResult);
-
- log.info("空头信号检查, 200日EMA价格{}位于下方: {}, 死叉: {}, MACD柱状线由正转负: {}, 顶背离: {}",
- latestTrendEma,isBelowTrend, isDeathCross, isMacdHistTurningNegative, isTopDivergence);
-
- // 空头开仓条件:柱状线转弱 + 死叉 + (趋势向下或顶背离)
- return isMacdHistTurningNegative && isDeathCross && ( isBelowTrend || isTopDivergence);
- }
-
- // 平仓条件检查方法
-
- /**
- * 多头平仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param currentPrice 当前价格
- * @return 是否满足多头平仓条件
- */
- private boolean isLongExitCondition(MACDResult macdResult, BigDecimal currentPrice) {
- // 多头平仓条件:MACD柱状线动量减弱(由正转弱)
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() >= 2) {
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由正转弱:前一根为正,当前绝对值减小
- boolean momentumWeakening = previous.getMacdHist().compareTo(BigDecimal.ZERO) >= 0 &&
- latest.getMacdHist().abs().compareTo(previous.getMacdHist().abs()) < 0;
-
- return momentumWeakening;
- }
- return false;
- }
-
- /**
- * 空头平仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param currentPrice 当前价格
- * @return 是否满足空头平仓条件
- */
- private boolean isShortExitCondition(MACDResult macdResult, BigDecimal currentPrice) {
- // 空头平仓条件:MACD柱状线动量减弱(由负转弱)
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() >= 2) {
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由负转弱:前一根为负,当前绝对值减小
- boolean momentumWeakening = previous.getMacdHist().compareTo(BigDecimal.ZERO) <= 0 &&
- latest.getMacdHist().abs().compareTo(previous.getMacdHist().abs()) < 0;
-
- return momentumWeakening;
- }
-
- return false;
- }
-
- // MACD信号辅助方法
-
- /**
- * 简单金叉判断
- * <p>
- * 条件:DIF线从下往上穿过DEA线
- *
- * @param macdResult MACD计算结果
- * @return 是否形成金叉
- */
- private boolean isGoldenCross(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0);
- PriceData previous = macdData.get(1);
-
- // 金叉判断:DIF从下往上穿过DEA
- return previous.getDif().compareTo(previous.getDea()) < 0 &&
- latest.getDif().compareTo(latest.getDea()) > 0;
- }
-
- /**
- * 简单死叉判断
- * <p>
- * 条件:DIF线从上往下穿过DEA线
- *
- * @param macdResult MACD计算结果
- * @return 是否形成死叉
- */
- private boolean isDeathCross(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0);
- PriceData previous = macdData.get(1);
-
- // 死叉判断:DIF从上往下穿过DEA
- return previous.getDif().compareTo(previous.getDea()) > 0 &&
- latest.getDif().compareTo(latest.getDea()) < 0;
- }
-
- /**
- * MACD柱状线由负转正判断
- * <p>
- * 条件:前一根柱状线为负,当前柱状线为正
- *
- * @param macdResult MACD计算结果
- * @return 是否由负转正
- */
- private boolean isMacdHistTurningPositive(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由负转正:前一根为负,当前为正
- return previous.getMacdHist().compareTo(BigDecimal.ZERO) <= 0 &&
- latest.getMacdHist().compareTo(BigDecimal.ZERO) > 0;
- }
-
- /**
- * MACD柱状线由正转负判断
- * <p>
- * 条件:前一根柱状线为正,当前柱状线为负
- *
- * @param macdResult MACD计算结果
- * @return 是否由正转负
- */
- private boolean isMacdHistTurningNegative(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由正转负:前一根为正,当前为负
- return previous.getMacdHist().compareTo(BigDecimal.ZERO) >= 0 &&
- latest.getMacdHist().compareTo(BigDecimal.ZERO) < 0;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java
deleted file mode 100644
index f5ebaf3..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/**
- * MACD和MA组合交易策略实现类
- * 基于多时间粒度K线数据生成交易信号并确定持仓方向
- *
- * 该策略综合考虑了EMA指标、MACD指标、价格突破信号和波动率因素,
- * 形成了一套完整的开仓、平仓和持仓管理机制。
- * 支持1分钟(K线)和日线(K线)级别的数据输入,数据顺序要求从新到旧排列。
- */
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * MACD和MA组合交易策略实现
- * <p>
- * 该策略利用EMA交叉、MACD指标、价格突破信号和波动率过滤,
- * 为多时间粒度K线级别交易提供综合决策支持。
- * <p>
- * 数据输入要求:
- * - historicalPrices1M:1分钟K线收盘价列表,顺序从新到旧
- * - historicalPrices1D:日线K线收盘价列表,顺序从新到旧
- */
-@Slf4j
-public class MacdMaStrategy {
-
- /** 操作类型枚举 */
- public enum OperationType {
- /** 开仓 */
- open,
- /** 平仓 */
- close
- }
-
- /** 持仓状态枚举 */
- public enum PositionType {
- /** 多头开仓 */
- LONG_BUY,
- /** 多头平仓 */
- LONG_SELL,
- /** 空头开仓 */
- SHORT_SELL,
- /** 空头平仓 */
- SHORT_BUY,
- /** 空仓 */
- NONE
- }
-
- /** 交易指令类,封装side和posSide的组合 */
- public static class TradingOrder {
- private String side; // buy或sell
- private String posSide; // long或short
-
- public TradingOrder(String side, String posSide) {
- this.side = side;
- this.posSide = posSide;
- }
-
- public String getSide() {
- return side;
- }
-
- public String getPosSide() {
- return posSide;
- }
-
- @Override
- public String toString() {
- return String.format("TradingOrder{side='%s', posSide='%s'}", side, posSide);
- }
- }
-
- // 策略参数
- private int shortPeriod; // 短期EMA周期
- private int longPeriod; // 长期EMA周期
- private int signalPeriod; // MACD信号线周期
- private int volatilityPeriod; // 波动率计算周期
- private int trendPeriod = 200; // 趋势过滤EMA周期(200日)
- private BigDecimal stopLossRatio; // 止损比例
- private BigDecimal takeProfitRatio; // 止盈比例
-
- /**
- * 默认构造函数,使用标准MACD参数
- * 短期周期=12, 长期周期=26, 信号线周期=9, 波动率周期=20
- * 止损比例=1%, 止盈比例=2%
- */
- public MacdMaStrategy() {
- this(12, 26, 9, 20, new BigDecimal("0.01"), new BigDecimal("0.02"));
- }
-
- /**
- * 自定义参数构造函数,使用默认趋势周期200
- *
- * @param shortPeriod 短期EMA周期
- * @param longPeriod 长期EMA周期
- * @param signalPeriod MACD信号线周期
- * @param volatilityPeriod 波动率计算周期
- * @param stopLossRatio 止损比例
- * @param takeProfitRatio 止盈比例
- */
- public MacdMaStrategy(int shortPeriod, int longPeriod, int signalPeriod, int volatilityPeriod,
- BigDecimal stopLossRatio, BigDecimal takeProfitRatio) {
- this(shortPeriod, longPeriod, signalPeriod, volatilityPeriod, 200, stopLossRatio, takeProfitRatio);
- }
-
- /**
- * 自定义参数构造函数
- *
- * @param shortPeriod 短期EMA周期
- * @param longPeriod 长期EMA周期
- * @param signalPeriod MACD信号线周期
- * @param volatilityPeriod 波动率计算周期
- * @param trendPeriod 趋势过滤EMA周期(200日)
- * @param stopLossRatio 止损比例
- * @param takeProfitRatio 止盈比例
- */
- public MacdMaStrategy(int shortPeriod, int longPeriod, int signalPeriod, int volatilityPeriod, int trendPeriod,
- BigDecimal stopLossRatio, BigDecimal takeProfitRatio) {
- this.shortPeriod = shortPeriod;
- this.longPeriod = longPeriod;
- this.signalPeriod = signalPeriod;
- this.volatilityPeriod = volatilityPeriod;
- this.trendPeriod = trendPeriod;
- this.stopLossRatio = stopLossRatio;
- this.takeProfitRatio = takeProfitRatio;
- }
-
- // 主流程方法
-
- /**
- * 分析历史价格数据并生成交易指令
- *
- * @param historicalPrices 历史价格序列(1分钟K线收盘价),顺序从新到旧
- * @param historical1DayPrices 日线历史价格序列,顺序从新到旧
- * @param operation 操作类型(open/close)
- * @return 交易指令(包含side和posSide),如果没有交易信号则返回null
- */
- public TradingOrder generateTradingOrder(List<BigDecimal> historicalPrices, List<BigDecimal> historical1DayPrices, String operation) {
- PositionType signal = null;
-
- if (OperationType.open.name().equals(operation)) {
- signal = analyzeOpen(historicalPrices, historical1DayPrices);
- } else if (OperationType.close.name().equals(operation)) {
- signal = analyzeClose(historicalPrices, historical1DayPrices);
- }
-
- // 根据信号生成交易指令
- return convertSignalToTradingOrder(signal);
- }
-
- /**
- * 分析最新价格数据并生成开仓信号
- *
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
- * @return 生成的交易信号(LONG_BUY、SHORT_SELL或NONE)
- */
- public PositionType analyzeOpen(List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
- // 数据检查:确保有足够的数据点进行计算(需要足够数据计算200日EMA)
- if (closePrices == null || closePrices.size() < Math.max(34, trendPeriod) ||
- close1DPrices == null || close1DPrices.size() < Math.max(34, trendPeriod)) {
- return PositionType.NONE; // 数据不足,无法生成信号
- }
-
- // 计算MACD指标
- MACDResult macdResult = MACDCalculator.calculateMACD(
- closePrices, shortPeriod, longPeriod, signalPeriod);
- log.info("MACD计算结果:{}", macdResult.getMacdData().get(0));
-
- // 多头开仓条件检查
- if (isLongEntryCondition(macdResult, closePrices, close1DPrices)) {
- log.info("多头开仓信号,价格:{}", closePrices.get(0));
- return PositionType.LONG_BUY;
- }
-
- // 空头开仓条件检查
- if (isShortEntryCondition(macdResult, closePrices, close1DPrices)) {
- log.info("空头开仓信号,价格:{}", closePrices.get(0));
- return PositionType.SHORT_SELL;
- }
-
- // 无信号
- return PositionType.NONE;
- }
-
- /**
- * 分析最新价格数据并生成平仓信号
- *
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
- * @return 生成的交易信号(LONG_SELL、SHORT_BUY或NONE)
- */
- public PositionType analyzeClose(List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
- // 数据检查:确保有足够的数据点进行计算
- if (closePrices == null || closePrices.size() < Math.max(34, trendPeriod) ||
- close1DPrices == null || close1DPrices.size() < Math.max(34, trendPeriod)) {
- return PositionType.NONE; // 数据不足,无法生成信号
- }
-
- // 计算MACD指标
- MACDResult macdResult = MACDCalculator.calculateMACD(
- closePrices, shortPeriod, longPeriod, signalPeriod);
-
- // 最新收盘价
- BigDecimal latestPrice = closePrices.get(0);
-
- if (isLongExitCondition(macdResult, latestPrice)) {
- log.info("多头平仓信号,价格:{}", latestPrice);
- return PositionType.LONG_SELL;
- }
-
- if (isShortExitCondition(macdResult, latestPrice)) {
- log.info("空头平仓信号,价格:{}", latestPrice);
- return PositionType.SHORT_BUY;
- }
-
- // 无信号
- return PositionType.NONE;
- }
-
- // 信号转换方法
-
- /**
- * 将持仓信号转换为交易指令
- *
- * @param signal 持仓信号
- * @return 交易指令,无信号则返回null
- */
- private TradingOrder convertSignalToTradingOrder(PositionType signal) {
- if (signal == null) {
- return null;
- }
-
- switch (signal) {
- case LONG_BUY:
- // 开多:买入开多(side 填写 buy; posSide 填写 long )
- return new TradingOrder("buy", "long");
- case LONG_SELL:
- // 平多:卖出平多(side 填写 sell; posSide 填写 long )
- return new TradingOrder("sell", "long");
- case SHORT_SELL:
- // 开空:卖出开空(side 填写 sell; posSide 填写 short )
- return new TradingOrder("sell", "short");
- case SHORT_BUY:
- // 平空:买入平空(side 填写 buy; posSide 填写 short )
- return new TradingOrder("buy", "short");
- default:
- // 无信号
- return null;
- }
- }
-
- // 开仓条件检查方法
-
- /**
- * 多头开仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
- * @return 是否满足多头开仓条件
- */
- private boolean isLongEntryCondition(MACDResult macdResult, List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
- // 1. 计算200日EMA(趋势过滤)
- // 复制并反转日线数据,确保从旧到新计算EMA
- List<BigDecimal> reversed1DPrices = new ArrayList<>(close1DPrices);
- Collections.reverse(reversed1DPrices);
- List<BigDecimal> trendEma = EMACalculator.calculateEMA(reversed1DPrices, trendPeriod, true);
- BigDecimal latestTrendEma = trendEma.get(trendEma.size() - 1);
- BigDecimal latestPrice = closePrices.get(0);
- log.info( "200日EMA:{}, 最新价格:{}", latestTrendEma, latestPrice);
-
- // 2. 价格必须位于200日EMA上方(多头趋势确认)
- boolean isAboveTrend = latestPrice.compareTo(latestTrendEma) > 0;
-
- // 3. MACD金叉检查
- boolean isGoldenCross = isGoldenCross(macdResult);
-
- // 4. MACD柱状线由负转正(动量转变)
- boolean isMacdHistTurningPositive = isMacdHistTurningPositive(macdResult);
-
- // 5. 底背离检查(增强多头信号可靠性)
- boolean isBottomDivergence = MACDCalculator.isBottomDivergence(closePrices, macdResult);
-
- log.info("多头信号检查, 价格位于200日EMA上方: {}, 金叉: {}, MACD柱状线由负转正: {}, 底背离: {}",
- isAboveTrend, isGoldenCross, isMacdHistTurningPositive, isBottomDivergence);
-
- // 多头开仓条件:趋势向上 + 金叉 + (柱状线转强或底背离)
- return isAboveTrend && isGoldenCross && (isMacdHistTurningPositive || isBottomDivergence);
- }
-
- /**
- * 空头开仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
- * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
- * @return 是否满足空头开仓条件
- */
- private boolean isShortEntryCondition(MACDResult macdResult, List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
- // 1. 计算200日EMA(趋势过滤)
- // 复制并反转日线数据,确保从旧到新计算EMA
- List<BigDecimal> reversed1DPrices = new ArrayList<>(close1DPrices);
- Collections.reverse(reversed1DPrices);
- List<BigDecimal> trendEma = EMACalculator.calculateEMA(reversed1DPrices, trendPeriod, true);
- BigDecimal latestTrendEma = trendEma.get(trendEma.size() - 1);
- BigDecimal latestPrice = closePrices.get(0);
-
- log.info( "200日EMA:{}, 最新价格:{}", latestTrendEma, latestPrice);
-
- // 2. 价格必须位于200日EMA下方(空头趋势确认)
- boolean isBelowTrend = latestPrice.compareTo(latestTrendEma) < 0;
-
- // 3. MACD死叉检查
- boolean isDeathCross = isDeathCross(macdResult);
-
- // 4. MACD柱状线由正转负(动量转变)
- boolean isMacdHistTurningNegative = isMacdHistTurningNegative(macdResult);
-
- // 5. 顶背离检查(增强空头信号可靠性)
- boolean isTopDivergence = MACDCalculator.isTopDivergence(closePrices, macdResult);
-
- log.info("空头信号检查, 价格位于200日EMA下方: {}, 死叉: {}, MACD柱状线由正转负: {}, 顶背离: {}",
- isBelowTrend, isDeathCross, isMacdHistTurningNegative, isTopDivergence);
-
- // 空头开仓条件:趋势向下 + 死叉 + (柱状线转弱或顶背离)
- return isBelowTrend && isDeathCross && (isMacdHistTurningNegative || isTopDivergence);
- }
-
- // 平仓条件检查方法
-
- /**
- * 多头平仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param currentPrice 当前价格
- * @return 是否满足多头平仓条件
- */
- private boolean isLongExitCondition(MACDResult macdResult, BigDecimal currentPrice) {
- // 多头平仓条件:MACD柱状线动量减弱(由正转弱)
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() >= 2) {
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由正转弱:前一根为正,当前绝对值减小
- boolean momentumWeakening = previous.getMacdHist().compareTo(BigDecimal.ZERO) >= 0 &&
- latest.getMacdHist().abs().compareTo(previous.getMacdHist().abs()) < 0;
-
- return momentumWeakening;
- }
- return false;
- }
-
- /**
- * 空头平仓条件检查
- *
- * @param macdResult MACD计算结果
- * @param currentPrice 当前价格
- * @return 是否满足空头平仓条件
- */
- private boolean isShortExitCondition(MACDResult macdResult, BigDecimal currentPrice) {
- // 空头平仓条件:MACD柱状线动量减弱(由负转弱)
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() >= 2) {
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由负转弱:前一根为负,当前绝对值减小
- boolean momentumWeakening = previous.getMacdHist().compareTo(BigDecimal.ZERO) <= 0 &&
- latest.getMacdHist().abs().compareTo(previous.getMacdHist().abs()) < 0;
-
- return momentumWeakening;
- }
-
- return false;
- }
-
- // MACD信号辅助方法
-
- /**
- * 简单金叉判断
- * <p>
- * 条件:DIF线从下往上穿过DEA线
- *
- * @param macdResult MACD计算结果
- * @return 是否形成金叉
- */
- private boolean isGoldenCross(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0);
- PriceData previous = macdData.get(1);
-
- // 金叉判断:DIF从下往上穿过DEA
- return previous.getDif().compareTo(previous.getDea()) < 0 &&
- latest.getDif().compareTo(latest.getDea()) > 0;
- }
-
- /**
- * 简单死叉判断
- * <p>
- * 条件:DIF线从上往下穿过DEA线
- *
- * @param macdResult MACD计算结果
- * @return 是否形成死叉
- */
- private boolean isDeathCross(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0);
- PriceData previous = macdData.get(1);
-
- // 死叉判断:DIF从上往下穿过DEA
- return previous.getDif().compareTo(previous.getDea()) > 0 &&
- latest.getDif().compareTo(latest.getDea()) < 0;
- }
-
- /**
- * MACD柱状线由负转正判断
- * <p>
- * 条件:前一根柱状线为负,当前柱状线为正
- *
- * @param macdResult MACD计算结果
- * @return 是否由负转正
- */
- private boolean isMacdHistTurningPositive(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由负转正:前一根为负,当前为正
- return previous.getMacdHist().compareTo(BigDecimal.ZERO) <= 0 &&
- latest.getMacdHist().compareTo(BigDecimal.ZERO) > 0;
- }
-
- /**
- * MACD柱状线由正转负判断
- * <p>
- * 条件:前一根柱状线为正,当前柱状线为负
- *
- * @param macdResult MACD计算结果
- * @return 是否由正转负
- */
- private boolean isMacdHistTurningNegative(MACDResult macdResult) {
- List<PriceData> macdData = macdResult.getMacdData();
- if (macdData.size() < 2) {
- return false;
- }
-
- PriceData latest = macdData.get(0); // 最新数据
- PriceData previous = macdData.get(1); // 前一个数据
-
- // 柱状线由正转负:前一根为正,当前为负
- return previous.getMacdHist().compareTo(BigDecimal.ZERO) >= 0 &&
- latest.getMacdHist().compareTo(BigDecimal.ZERO) < 0;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/PriceData.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/PriceData.java
deleted file mode 100644
index 38f61e8..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/PriceData.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * 价格数据实体类
- * <p>
- * 用于存储K线的价格数据及其衍生指标值。作为MACD和MA策略计算过程中的数据载体,
- * 包含收盘价、指数移动平均线、MACD指标等关键价格和指标信息。
- */
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import java.math.BigDecimal;
-
-/**
- * 价格数据类,封装单条K线的价格信息及相关技术指标数据
- * 使用BigDecimal确保金融计算的精确性
- */
-public class PriceData {
- /** 收盘价 */
- private BigDecimal close;
-
- /** 短期指数移动平均线(通常为12周期) */
- private BigDecimal emaShort;
-
- /** 长期指数移动平均线(通常为26周期) */
- private BigDecimal emaLong;
-
- /** DIF值(短期EMA与长期EMA的差值) */
- private BigDecimal dif;
-
- /** DEA值(DIF的移动平均线,通常为9周期EMA) */
- private BigDecimal dea;
-
- /** MACD柱状图值(DIF与DEA的差值) */
- private BigDecimal macdHist;
-
- /**
- * 构造函数,创建价格数据对象
- *
- * @param close 收盘价
- */
- public PriceData(BigDecimal close) {
- this.close = close;
- }
-
- /**
- * 获取收盘价
- *
- * @return 收盘价
- */
- public BigDecimal getClose() {
- return close;
- }
-
- /**
- * 设置收盘价
- *
- * @param close 收盘价
- */
- public void setClose(BigDecimal close) {
- this.close = close;
- }
-
- /**
- * 获取短期EMA值
- *
- * @return 短期EMA值
- */
- public BigDecimal getEmaShort() {
- return emaShort;
- }
-
- /**
- * 设置短期EMA值
- *
- * @param emaShort 短期EMA值
- */
- public void setEmaShort(BigDecimal emaShort) {
- this.emaShort = emaShort;
- }
-
- /**
- * 获取长期EMA值
- *
- * @return 长期EMA值
- */
- public BigDecimal getEmaLong() {
- return emaLong;
- }
-
- /**
- * 设置长期EMA值
- *
- * @param emaLong 长期EMA值
- */
- public void setEmaLong(BigDecimal emaLong) {
- this.emaLong = emaLong;
- }
-
- /**
- * 获取DIF值
- *
- * @return DIF值
- */
- public BigDecimal getDif() {
- return dif;
- }
-
- /**
- * 设置DIF值
- *
- * @param dif DIF值
- */
- public void setDif(BigDecimal dif) {
- this.dif = dif;
- }
-
- /**
- * 获取DEA值
- *
- * @return DEA值
- */
- public BigDecimal getDea() {
- return dea;
- }
-
- /**
- * 设置DEA值
- *
- * @param dea DEA值
- */
- public void setDea(BigDecimal dea) {
- this.dea = dea;
- }
-
- /**
- * 获取MACD柱状图值
- *
- * @return MACD柱状图值
- */
- public BigDecimal getMacdHist() {
- return macdHist;
- }
-
- /**
- * 设置MACD柱状图值
- *
- * @param macdHist MACD柱状图值
- */
- public void setMacdHist(BigDecimal macdHist) {
- this.macdHist = macdHist;
- }
-
- /**
- * 转换为字符串表示
- *
- * @return 格式化的字符串表示
- */
- @Override
- public String toString() {
- return String.format("PriceData{close=%.2f, EMA_short=%.2f, EMA_long=%.2f, DIF=%.2f, DEA=%.2f, MACD_hist=%.2f}",
- close.doubleValue(), emaShort.doubleValue(), emaLong.doubleValue(),
- dif.doubleValue(), dea.doubleValue(), macdHist.doubleValue());
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/Volatility.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/Volatility.java
deleted file mode 100644
index f4d1543..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/Volatility.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * 波动率指标计算类
- * <p>
- * 波动率是衡量金融市场价格波动程度的指标,通常用价格的标准差与平均值的比率表示。
- * 本类实现了基于滚动窗口的波动率计算,通过标准差与平均值的比值计算出百分比形式的波动率。
- */
-package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * 波动率指标实现类
- * <p>波动率计算原理:使用标准差与平均值的比值,以百分比形式表示价格的波动程度。</p>
- * <p>计算公式:波动率 = (标准差 / 平均值) * 100%</p>
- *
- * <p>使用示例:</p>
- * <pre>
- * // 初始化20日波动率计算器
- * Volatility vol = new Volatility(20);
- *
- * // 动态添加每日价格
- * priceFeed.subscribe(price -> {
- * vol.addPrice(price);
- * vol.calculate();
- * });
- *
- * // 判断是否满足低波动条件(<1%)
- * if (vol.getValue().compareTo(new BigDecimal("1.00")) < 0) {
- * System.out.println("低波动市场,暂停交易");
- * }
- * </pre>
- */
-public class Volatility {
- /** 波动率计算的周期(如20日波动率) */
- private final int period;
-
- /** 当前计算出的波动率值(百分比形式) */
- private BigDecimal volatility = BigDecimal.ZERO;
-
- /** 使用LinkedList存储滚动窗口内的价格数据,便于添加和删除操作 */
- private LinkedList<BigDecimal> priceWindow = new LinkedList<>();
-
- /** 窗口内价格的总和,用于快速计算平均值 */
- private BigDecimal sum = BigDecimal.ZERO;
-
- /** 窗口内价格平方的总和,用于快速计算方差 */
- private BigDecimal sumSquares = BigDecimal.ZERO;
-
- /**
- * 构造函数,创建指定周期的波动率计算器
- *
- * @param period 波动率计算周期,如20表示计算20日波动率
- */
- public Volatility(int period) {
- this.period = period;
- }
-
- /**
- * 添加新价格到计算窗口,并维护窗口内的价格数据
- * 采用滑动窗口方式,当价格数量超过周期时,自动移除最早的价格
- *
- * @param price 新的价格数据,使用BigDecimal确保计算精度
- * @throws IllegalArgumentException 当价格为null时抛出异常
- */
- public void addPrice(BigDecimal price) {
- if (price == null) {
- throw new IllegalArgumentException("Price cannot be null");
- }
-
- // 当窗口大小达到周期时,移除最早的价格,并从总和中减去
- if (priceWindow.size() == period) {
- BigDecimal removed = priceWindow.removeFirst();
- sum = sum.subtract(removed);
- sumSquares = sumSquares.subtract(removed.pow(2));
- }
-
- // 添加新价格到窗口,并更新总和
- priceWindow.add(price);
- sum = sum.add(price);
- sumSquares = sumSquares.add(price.pow(2));
- }
-
- /**
- * 计算当前窗口内价格的波动率
- * 使用标准差与平均值的比值计算波动率百分比
- */
- public void calculate() {
- // 数据点不足,无法计算波动率
- if (priceWindow.size() < period) {
- return;
- }
-
- // 计算平均值:sum / period
- BigDecimal avg = sum.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP);
-
- // 防止除以零的情况
- if (avg.compareTo(BigDecimal.ZERO) == 0) {
- volatility = BigDecimal.ZERO;
- return;
- }
-
- // 计算方差:(sumSquares / period) - avg^2
- BigDecimal variance = sumSquares.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP)
- .subtract(avg.pow(2));
-
- // 确保方差非负(防止浮点数计算误差导致负数方差)
- variance = variance.max(BigDecimal.ZERO);
-
- // 计算标准差:sqrt(variance)
- BigDecimal stdDev = sqrt(variance, 8);
-
- // 计算波动率:(标准差 / 平均值) * 100%
- volatility = stdDev.divide(avg, 8, RoundingMode.HALF_UP)
- .multiply(new BigDecimal(100))
- .setScale(2, RoundingMode.HALF_UP);
- }
-
- /**
- * 计算BigDecimal的平方根(使用牛顿迭代法)
- *
- * @param value 要计算平方根的数值
- * @param scale 结果的精度(小数位数)
- * @return 平方根结果
- */
- private BigDecimal sqrt(BigDecimal value, int scale) {
- // 负数没有实数平方根,返回0
- if (value.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimal.ZERO;
- }
-
- // 使用牛顿迭代法计算平方根
- BigDecimal x = value.divide(new BigDecimal(2), scale, RoundingMode.HALF_UP); // 初始猜测值
- BigDecimal prev;
-
- do {
- prev = x;
- // 牛顿迭代公式:x(n+1) = (x(n) + value/x(n))/2
- // 添加零检查,防止除以零异常
- if (x.compareTo(BigDecimal.ZERO) == 0) {
- x = new BigDecimal(1); // 设置一个合理的初始值
- }
- x = x.add(value.divide(x, scale, RoundingMode.HALF_UP)).divide(new BigDecimal(2), scale, RoundingMode.HALF_UP);
- } while (x.subtract(prev).abs().compareTo(BigDecimal.ONE.movePointLeft(scale)) > 0); // 直到满足精度要求
-
- return x;
- }
-
- /**
- * 获取最新的波动率计算结果
- *
- * @return 波动率值,以百分比形式表示(例如:2.5表示2.5%)
- */
- public BigDecimal getValue() {
- return volatility;
- }
-}
\ No newline at end of file
diff --git "a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/\345\206\205\345\256\271" "b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/\345\206\205\345\256\271"
deleted file mode 100644
index 16e57d4..0000000
--- "a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/\345\206\205\345\256\271"
+++ /dev/null
@@ -1,107 +0,0 @@
-MACD 是什麼?三個核心組成介紹
-MACD 全名為 Moving Average Convergence Divergence,中文為平滑異同移動平均線,它主要是透過快線 DIF、慢線 DEA、能量柱 Histogram三個成分組成,用以幫助投資者捕捉股價或資產價格的趨勢變化、動能強弱以及潛在的買賣訊號。
-
-MACD
-
-MACD 指標主要由三個核心構成,每個核心皆有各自的涵義,讓投資者對於市場動態清楚明瞭:
-
-快線 DIF(DIFferential Line)-差離值
-
-DIF 是 MACD 的核心快線,是 MACD 中主要用來判斷市場長短期趨勢差異的工具,DIF 波動較快的特性也使得投資者可以透過其捕捉更敏銳的短期變化,當 DIF 上漲時表示短期動能增強,反之則減弱。
-
-快線 DIF(DIFferential Line)
-
-慢線 DEA(DIFference Exponential Average)-訊號線
-
-慢線 DEA 又稱為 Signal 訊號線,曲線通常較為平滑,能夠用以輔佐投資者過濾 DIF 的雜訊,提供更穩定的趨勢確認訊號。當 DIF 穿越 DEA 向上時,常被視作買入訊號(黃金交叉),反之則為賣出訊號(死亡交叉)。
-
-慢線 DEA(DIFference Exponential Average)-訊號線
-
-能量柱(Histogram)
-
-Histogram 是 MACD 的柱狀圖部分,由快線 DIF 減去慢線 DEA 得來,柱狀圖的高度反映快線與慢線的差距,當正柱狀圖(零軸之上)愈來愈高時表示多頭動能增強,負柱狀圖(零軸之下)愈來愈低時表示空頭動能增強,而柱狀圖逐漸收斂時則可能表示趨勢即將反轉。
-
-能量柱(Histogram)
-
-MACD公式計算詳細解析
-要深入理解 MACD 指標首先必須先掌握其數值的算法並得知運算結果,MACD 的計算主要基於指數移動平均線(EMA),並通過一系列簡單的數學公式計算得出 DIF、DEA 和柱狀圖。
-
-EMA(Exponential Moving Average)介紹
-
-EMA 中文為指數移動平均線,與簡單移動平均線(SMA)不同的是,EMA 對近期價格數據給予更高的權重,使得它對價格變化的反應更為靈敏。
-
-EMA 的運算公式為:【今日收盤價 × α】 + 【昨日 EMA × (1 − α)】
-
-其中,α(平滑因子)= 2/(N + 1),N 為選定的周期數。例如,12 期 EMA 的 α = 2/(12 + 1) ≈ 0.1538。初次計算 EMA 時,若無前一日的 EMA,可使用該周期的簡單移動平均(SMA)作為起點。EMA 的靈敏性使 MACD 更能快速反映市場動態。
-
-EMA
-
-快線 DIF 計算方式
-
-DIF 作為 MACD 核心之一,計算方式為:EMA(12)-EMA(26)。
-
-EMA 12 代表短期價格趨勢(較快反應),而 EMA 26 代表長期趨勢(較平滑)。當短期 EMA 高於長期 EMA 時,DIF 為正值,表示短期動能強於長期動能,暗示看漲;反之,DIF 為負值則暗示看跌。這之間的差值能幫助投資者快速判斷趨勢的強弱與方向。
-
-慢線 DEA 計算方式
-
-DEA 計算方式為:EMA(DIF,9)
-
-這樣的計算方式將 DIF 的曲線進一步平滑,減少短期價格噪音的干擾,提供更穩定的趨勢指標。DEA 線的作用在於與 DIF 形成交叉訊號,例如 DIF 上穿 DEA 線(黃金交叉)通常被視為買入訊號,而下穿(死亡交叉)則為賣出訊號。
-
-柱狀圖 Histogram 計算方式
-
-Histogram 作為 MACD 指標唯一的圖形,計算方式為:DIF − DEA
-
-柱狀圖直觀顯示快線與慢線的差距,當 DIF 大於 DEA 時,柱狀圖為正時,表示多頭動能增強,反之柱狀圖為負時,表示空頭力量占優。
-
-MACD 公式實盤範例解析
-為了更直觀的理解 MACD 在實盤上的計算過程,我們以幣安的 ETHUSDT 圖表進行 MACD 試算。
-
-第一步驟:新增 EMA 指標
-
-由於 MACD 中的快線、慢線計算過程中皆會使用到 EMA 指標,因此我們可以直接新增 EMA 指標並進行參數調整即可計算 MACD 相關參數。
-
-第二步驟:計算 MACD 中的快線 DIF
-
-快線 DIF 的計算方式為 EMA(12)-EMA(26),因此我們只要將兩條 EMA 指標分別設定為 12、26 並進行相減即可,例如下圖中 EMA 12 為 4271.55,EMA 26 為 3941.88,相減即得 329.67,這一數字與 MACD 中顯示的快線 DIF 相同。
-
-第三步驟:計算 MACD 中的慢線 DEA
-
-慢線的公式為:EMA(DIF,9),其中 9 代表周期數,EMA 的計算使用平滑因子 α = 2 ÷ (9 + 1) = 0.2,因此 MACD 中的慢線 DEA 計算公式為:【今日 DIF*0.2】+【昨日 DEA*0.8】。
-
-今日 DIF 為 329.67,而昨日 DEA 為 250.86,套入計算公式 329.67*0.2+250.86*0.8=266.62,這一數字同樣與 MACD 中顯示的慢線 DEA 相同。
-
-第四步驟:計算 MACD 中的柱狀圖 Histogram
-
-只要解出快線及慢線,要求出 MACD 中的柱狀圖就十分容易,僅需將快線減去慢線即可。上述計算出快線 DIF 數值為 329.67,而慢線 DEA 數值為 266.62,相減即可得出柱狀圖為 63.05,如此一來就得出 MACD 指標所需的所有數據。
-
-MACD公式
-
-MACD黃金/死亡交叉案例
-黃金交叉與死亡交叉是 MACD 指標中最為人所知的交易訊號,許多交易者會藉由黃金交叉與死亡交叉判斷行情趨勢。
-
-首先我們可以觀察到 ETHUSDT 在 4 月 13 號時快線 DIF 上穿慢線 DEA 形成有效金叉後,接下來不斷上漲,甚至直接開啟以太坊牛市。
-
-MACD金叉案例
-
-而再將時間往回推,可以看到在 2024 年 12 月 9 號時 MACD 快線下穿慢線形成死叉,並在接下來回撤超過 60%,當時若觀察到 MACD 為死叉的投資者即可避免該次下跌甚至進行空單布局。
-
-MACD死叉範例
-
-常見問題
-為什麼有的版本能量柱( Histogram) 會*2?
-
-有些版本的 MACD 會將柱狀圖放大一倍,目的是為了讓視覺效果更明顯,投資者即可更直接的觀察快線與慢線之間的差距變化。
-
-金叉、死叉一定會上漲、下跌嗎?
-
-不一定,金融市場中並沒有哪一個指標可以保證上漲、下跌,MACD 也不例外。且包括 MACD 在內的所有指標皆具有一定的延遲性,其中可能包含雜訊,因此建議搭配技術分析或其他指標一同使用。
-
-MACD 的參數可以修改嗎?
-
-MACD 的參數是可以隨個人喜好修改的,例如(5, 13, 5)適用於短期交易,(50, 200, 20) 則適合長期趨勢分析,不過修改 MACD 參數會影響指標的靈敏度,建議回測歷史數據以找到最適合的設定。
-
-小結
-本篇文章解析了 MACD 的核心,從 MACD 的計算基礎 EMA 平均線到快線、慢線和柱狀圖三大核心,以及結合 ETHUSDT 圖表展示了 EMA 推導 MACD 數值的計算過程,但指標真正的價值在於如何靈活應用並提升勝率。因此看完這篇文章的你如果對於 MACD 有濃厚興趣的話,趕快打開 MACD 指標並進行深入的覆盤研究吧!
-
-本報告僅供資訊分享之用,內容不構成任何形式的投資建議或決策依據。文中所引用的數據、分析與觀點均基於作者的研究與公開來源,可能存在不確定性或隨時變動的情況。讀者應根據自身情況及風險承受能力,審慎進行投資判斷。如需進一步指導,建議尋求專業顧問意見。
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/AbstractTechnicalIndicatorStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/AbstractTechnicalIndicatorStrategy.java
deleted file mode 100644
index a853473..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/AbstractTechnicalIndicatorStrategy.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator.strategy;
-
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 技术指标策略抽象基类,提供通用功能
- */
-@Slf4j
-@Getter
-@Setter
-public abstract class AbstractTechnicalIndicatorStrategy implements TechnicalIndicatorStrategy {
-
- protected static final int MAX_PRICE_HISTORY = 100; // 最大价格历史记录数量
- protected List<BigDecimal> priceHistory = new ArrayList<>();
- protected boolean initialized = false;
- protected String strategyName = ""; // 策略名称
-
- @Override
- public void initialize() {
- priceHistory.clear();
- initialized = true;
- log.info("策略初始化完成: {}", strategyName);
- }
-
- @Override
- public void updatePrices(List<BigDecimal> prices) {
- if (!initialized) {
- initialize();
- }
-
- if (prices == null || prices.isEmpty()) {
- return;
- }
-
- // 更新价格历史记录
- priceHistory.addAll(prices);
-
- // 限制价格历史记录数量
- if (priceHistory.size() > MAX_PRICE_HISTORY) {
- priceHistory = priceHistory.subList(priceHistory.size() - MAX_PRICE_HISTORY, priceHistory.size());
- }
-
- log.debug("价格历史记录更新完成,当前数量: {}", priceHistory.size());
- }
-
- @Override
- public boolean isValid() {
- return initialized;
- }
-
- /**
- * 创建交易请求参数
- * @param accountName 账户名称
- * @param markPx 当前标记价格
- * @param posSide 仓位方向
- * @param signal 交易信号
- * @return 交易请求参数
- */
- protected TradeRequestParam createTradeRequestParam(String accountName, String markPx, String posSide, TradeSignal signal) {
- TradeRequestParam param = new TradeRequestParam();
- param.setAccountName(accountName);
- param.setMarkPx(markPx);
- param.setPosSide(posSide);
-
- log.info("账户: {}, 价格: {}, 仓位方向: {}, 信号: {}",
- accountName, markPx, posSide, signal.getName());
-
- return param;
- }
-
- /**
- * 日志记录交易信号
- * @param accountName 账户名称
- * @param markPx 当前标记价格
- * @param signal 交易信号
- */
- protected void logSignal(String accountName, String markPx, TradeSignal signal) {
- log.info("策略: {}, 账户: {}, 价格: {}, 信号: {}",
- strategyName, accountName, markPx, signal.getName());
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/ComprehensiveTechnicalStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/ComprehensiveTechnicalStrategy.java
deleted file mode 100644
index a6c320c..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/ComprehensiveTechnicalStrategy.java
+++ /dev/null
@@ -1,351 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator.strategy;
-
-import com.xcong.excoin.modules.okxNewPrice.indicator.BOLL;
-import com.xcong.excoin.modules.okxNewPrice.indicator.KDJ;
-import com.xcong.excoin.modules.okxNewPrice.indicator.MACD;
-import com.xcong.excoin.modules.okxNewPrice.indicator.RSI;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * 综合技术指标策略实现类,整合MACD、KDJ、RSI、BOLL等指标生成交易信号
- */
-@Slf4j
-public class ComprehensiveTechnicalStrategy extends AbstractTechnicalIndicatorStrategy {
-
- private final MACD macd;
- private final KDJ kdj;
- private final RSI rsi;
- private final BOLL boll;
-
- private BigDecimal prevDif;
- private BigDecimal prevDea;
- private BigDecimal prevK;
- private BigDecimal prevD;
-
- public ComprehensiveTechnicalStrategy() {
- super();
- this.strategyName = "综合技术指标策略";
- this.macd = new MACD();
- this.kdj = new KDJ();
- this.rsi = new RSI();
- this.boll = new BOLL();
- this.prevDif = BigDecimal.ZERO;
- this.prevDea = BigDecimal.ZERO;
- this.prevK = new BigDecimal(50);
- this.prevD = new BigDecimal(50);
- }
-
- @Override
- public void initialize() {
- super.initialize();
- macd.setDif(BigDecimal.ZERO);
- macd.setDea(BigDecimal.ZERO);
- macd.setMacdBar(BigDecimal.ZERO);
- macd.setPrevFastEMA(null);
- macd.setPrevSlowEMA(null);
- macd.setPrevDea(null);
-
- kdj.setK(new BigDecimal(50));
- kdj.setD(new BigDecimal(50));
- kdj.setJ(new BigDecimal(50));
- kdj.setPrevK(new BigDecimal(50));
- kdj.setPrevD(new BigDecimal(50));
-
- rsi.setRsi(BigDecimal.ZERO);
- rsi.setPrevAvgGain(BigDecimal.ZERO);
- rsi.setPrevAvgLoss(BigDecimal.ZERO);
-
- boll.setMid(BigDecimal.ZERO);
- boll.setUpper(BigDecimal.ZERO);
- boll.setLower(BigDecimal.ZERO);
-
- prevDif = BigDecimal.ZERO;
- prevDea = BigDecimal.ZERO;
- prevK = new BigDecimal(50);
- prevD = new BigDecimal(50);
-
- log.info("综合技术指标策略初始化完成");
- }
-
- @Override
- public TradeRequestParam getSignal(String accountName, String markPx, String posSide) {
- if (!initialized || priceHistory.isEmpty()) {
- log.warn("策略未初始化或价格历史为空");
- return createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL);
- }
-
- try {
- BigDecimal currentPrice = new BigDecimal(markPx);
-
- // 计算所有技术指标
- macd.calculate(priceHistory);
- kdj.calculate(priceHistory);
- rsi.calculate(priceHistory);
- boll.calculate(priceHistory);
-
- // 生成交易信号
- TradeRequestParam param = analyzeSignal(accountName, markPx, posSide, currentPrice);
-
- // 更新历史指标值
- updateHistoricalIndicatorValues();
-
- return param;
- } catch (Exception e) {
- log.error("计算交易信号时发生异常", e);
- return createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL);
- }
- }
-
- /**
- * 分析技术指标生成交易信号
- */
- private TradeRequestParam analyzeSignal(String accountName, String markPx, String posSide, BigDecimal currentPrice) {
- TradeRequestParam param = createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL);
- param.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- param.setInstId(CoinEnums.HE_YUE.getCode());
- param.setTdMode(CoinEnums.CROSS.getCode());
- param.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode());
-
- // 检查冷静期
- String outStr = getAccountConfig(accountName, CoinEnums.OUT.name());
- if (OrderParamEnums.OUT_YES.getValue().equals(outStr)) {
- log.error("冷静中,不允许下单......");
- param.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return param;
- }
-
- TradeSignal signal = TradeSignal.NO_SIGNAL;
-
- // 根据多空方向分别分析信号
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- signal = analyzeLongSignal(currentPrice, posSide);
- } else if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- signal = analyzeShortSignal(currentPrice, posSide);
- } else {
- // 如果没有指定仓位方向,同时分析多头和空头信号
- TradeSignal longSignal = analyzeLongSignal(currentPrice, posSide);
- TradeSignal shortSignal = analyzeShortSignal(currentPrice, posSide);
-
- // 优先选择非NO_SIGNAL的信号
- if (longSignal != TradeSignal.NO_SIGNAL) {
- signal = longSignal;
- } else {
- signal = shortSignal;
- }
- }
-
- log.info("账户: {}, 价格: {}, 方向: {}, 生成信号: {}",
- accountName, markPx, posSide, signal.getName());
-
- // 设置信号参数
- setSignalParameters(param, signal);
-
- return param;
- }
-
- /**
- * 分析多头信号
- */
- private TradeSignal analyzeLongSignal(BigDecimal currentPrice, String posSide) {
- // 检查超卖条件
- if (rsi.isOversold() || rsi.isExtremelyOversold()) {
- // KDJ超卖且金叉
- if ((kdj.isOversold() && kdj.isGoldenCross()) ||
- (boll.isBreakLower(currentPrice) && macd.isGoldenCross(prevDif, prevDea))) {
- // 如果当前没有仓位,则开多
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_LONG;
- }
- // 如果当前是空头仓位,则平空
- if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_SHORT;
- }
- // 如果当前已经是多头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
- }
-
- // 检查超买条件
- if (rsi.isOverbought() || rsi.isExtremelyOverbought()) {
- // KDJ超买且死叉
- if ((kdj.isOverbought() && kdj.isDeathCross()) ||
- (boll.isBreakUpper(currentPrice) && macd.isDeathCross(prevDif, prevDea))) {
- // 如果当前是多头仓位,则平多
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_LONG;
- }
- // 如果当前没有仓位,则开空
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_SHORT;
- }
- // 如果当前已经是空头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
- }
-
- // 检查MACD金叉死叉
- if (macd.isGoldenCross(prevDif, prevDea)) {
- // 如果当前没有仓位,则开多
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_LONG;
- }
- // 如果当前是空头仓位,则平空
- if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_SHORT;
- }
- // 如果当前已经是多头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- } else if (macd.isDeathCross(prevDif, prevDea)) {
- // 如果当前是多头仓位,则平多
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_LONG;
- }
- // 如果当前没有仓位,则开空
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_SHORT;
- }
- // 如果当前已经是空头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- return TradeSignal.NO_SIGNAL;
- }
-
- /**
- * 分析空头信号
- */
- private TradeSignal analyzeShortSignal(BigDecimal currentPrice, String posSide) {
- // 检查超买条件
- if (rsi.isOverbought() || rsi.isExtremelyOverbought()) {
- // KDJ超买且死叉
- if ((kdj.isOverbought() && kdj.isDeathCross()) ||
- (boll.isBreakUpper(currentPrice) && macd.isDeathCross(prevDif, prevDea))) {
- // 如果当前没有仓位,则开空
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_SHORT;
- }
- // 如果当前是多头仓位,则平多
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_LONG;
- }
- // 如果当前已经是空头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
- }
-
- // 检查超卖条件
- if (rsi.isOversold() || rsi.isExtremelyOversold()) {
- // KDJ超卖且金叉
- if ((kdj.isOversold() && kdj.isGoldenCross()) ||
- (boll.isBreakLower(currentPrice) && macd.isGoldenCross(prevDif, prevDea))) {
- // 如果当前是空头仓位,则平空
- if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_SHORT;
- }
- // 如果当前没有仓位,则开多
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_LONG;
- }
- // 如果当前已经是多头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
- }
-
- // 检查MACD金叉死叉
- if (macd.isGoldenCross(prevDif, prevDea)) {
- // 如果当前是空头仓位,则平空
- if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_SHORT;
- }
- // 如果当前没有仓位,则开多
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_LONG;
- }
- // 如果当前已经是多头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- } else if (macd.isDeathCross(prevDif, prevDea)) {
- // 如果当前没有仓位,则开空
- if (posSide == null || posSide.isEmpty()) {
- return TradeSignal.OPEN_SHORT;
- }
- // 如果当前是多头仓位,则平多
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- return TradeSignal.CLOSE_LONG;
- }
- // 如果当前已经是空头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- return TradeSignal.NO_SIGNAL;
- }
-
- /**
- * 设置信号参数
- */
- private void setSignalParameters(TradeRequestParam param, TradeSignal signal) {
- String side = null;
-
- switch (signal) {
- case BUY:
- side = CoinEnums.SIDE_BUY.getCode();
- break;
- case SELL:
- side = CoinEnums.SIDE_SELL.getCode();
- break;
- case OPEN_LONG:
- side = CoinEnums.SIDE_BUY.getCode();
- break;
- case CLOSE_LONG:
- side = CoinEnums.SIDE_SELL.getCode();
- break;
- case OPEN_SHORT:
- side = CoinEnums.SIDE_SELL.getCode();
- break;
- case CLOSE_SHORT:
- side = CoinEnums.SIDE_BUY.getCode();
- break;
- case STOP_LOSS:
- // 止损操作,根据当前仓位方向决定买卖方向
- side = CoinEnums.POSSIDE_LONG.getCode().equals(param.getPosSide()) ?
- CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode();
- break;
- default:
- param.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return;
- }
-
- param.setSide(side);
- log.info("设置交易方向: {}", side);
- }
-
- /**
- * 更新历史指标值
- */
- private void updateHistoricalIndicatorValues() {
- prevDif = macd.getDif();
- prevDea = macd.getDea();
- prevK = kdj.getK();
- prevD = kdj.getD();
- }
-
- /**
- * 获取账户配置信息
- */
- private String getAccountConfig(String accountName, String key) {
- try {
- // 这里需要根据实际情况获取账户配置信息
- // 暂时返回默认值,实际应该从InstrumentsWs或其他配置类中获取
- return "NO";
- } catch (Exception e) {
- log.error("获取账户配置信息失败", e);
- return "NO";
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/CoreTechnicalStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/CoreTechnicalStrategy.java
deleted file mode 100644
index 61469c5..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/CoreTechnicalStrategy.java
+++ /dev/null
@@ -1,589 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator.strategy;
-
-import com.xcong.excoin.modules.okxNewPrice.indicator.AdvancedMA;
-import com.xcong.excoin.modules.okxNewPrice.indicator.BOLL;
-import com.xcong.excoin.modules.okxNewPrice.indicator.KDJ;
-import com.xcong.excoin.modules.okxNewPrice.indicator.MACD;
-import com.xcong.excoin.modules.okxNewPrice.indicator.RSI;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 核心技术指标策略实现类
- * 整合三重EMA交叉系统、波动率自适应布林带、MACD能量柱分级策略等核心指标
- */
-@Slf4j
-public class CoreTechnicalStrategy extends AbstractTechnicalIndicatorStrategy {
-
- private static final int MACD_HISTOGRAM_PERIOD = 5; // MACD能量柱计算周期
- private static final BigDecimal VOLUME_MULTIPLIER = new BigDecimal(3); // 成交量放大倍数
- private static final BigDecimal GLUE_THRESHOLD = new BigDecimal(2); // 三线粘合度阈值(%)
-
- private final AdvancedMA advancedMA;
- private final BOLL boll;
- private final MACD macd;
- private final RSI rsi;
- private final KDJ kdj;
-
- private List<BigDecimal> macdHistogramHistory; // MACD能量柱历史
- private BigDecimal prevEma9;
- private BigDecimal prevEma21;
- private BigDecimal prevEma55;
- private BigDecimal prevDif;
- private BigDecimal prevDea;
- private BigDecimal prevK;
- private BigDecimal prevD;
- private BigDecimal prevJ;
-
- public CoreTechnicalStrategy() {
- super();
- this.strategyName = "核心技术指标策略";
- this.advancedMA = new AdvancedMA();
- this.boll = new BOLL();
- this.macd = new MACD();
- this.rsi = new RSI();
- this.kdj = new KDJ();
- this.macdHistogramHistory = new ArrayList<>();
- this.prevEma9 = BigDecimal.ZERO;
- this.prevEma21 = BigDecimal.ZERO;
- this.prevEma55 = BigDecimal.ZERO;
- this.prevDif = BigDecimal.ZERO;
- this.prevDea = BigDecimal.ZERO;
- this.prevK = new BigDecimal(50);
- this.prevD = new BigDecimal(50);
- this.prevJ = new BigDecimal(50);
- }
-
- @Override
- public void initialize() {
- super.initialize();
- macdHistogramHistory.clear();
-
- // 初始化技术指标
- advancedMA.setPrevEma9(null);
- advancedMA.setPrevEma21(null);
- advancedMA.setPrevEma55(null);
-
- macd.setDif(BigDecimal.ZERO);
- macd.setDea(BigDecimal.ZERO);
- macd.setMacdBar(BigDecimal.ZERO);
- macd.setPrevFastEMA(null);
- macd.setPrevSlowEMA(null);
- macd.setPrevDea(null);
-
- rsi.setRsi(BigDecimal.ZERO);
- rsi.setPrevAvgGain(BigDecimal.ZERO);
- rsi.setPrevAvgLoss(BigDecimal.ZERO);
-
- kdj.setK(new BigDecimal(50));
- kdj.setD(new BigDecimal(50));
- kdj.setJ(new BigDecimal(50));
- kdj.setPrevK(new BigDecimal(50));
- kdj.setPrevD(new BigDecimal(50));
-
- boll.setMid(BigDecimal.ZERO);
- boll.setUpper(BigDecimal.ZERO);
- boll.setLower(BigDecimal.ZERO);
-
- prevEma9 = BigDecimal.ZERO;
- prevEma21 = BigDecimal.ZERO;
- prevEma55 = BigDecimal.ZERO;
- prevDif = BigDecimal.ZERO;
- prevDea = BigDecimal.ZERO;
- prevK = new BigDecimal(50);
- prevD = new BigDecimal(50);
- prevJ = new BigDecimal(50);
-
- log.info("核心技术指标策略初始化完成");
- }
-
- @Override
- public TradeRequestParam getSignal(String accountName, String markPx, String posSide) {
- if (!initialized || priceHistory.isEmpty()) {
- log.warn("策略未初始化或价格历史为空");
- return createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL);
- }
-
- try {
- BigDecimal currentPrice = new BigDecimal(markPx);
-
- // 计算所有技术指标
- calculateIndicators(currentPrice);
-
- // 生成交易信号
- TradeRequestParam param = analyzeSignal(accountName, markPx, posSide, currentPrice);
-
- // 更新历史指标值
- updateHistoricalIndicatorValues();
-
- return param;
- } catch (Exception e) {
- log.error("计算交易信号时发生异常", e);
- return createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL);
- }
- }
-
- /**
- * 计算所有技术指标
- */
- private void calculateIndicators(BigDecimal currentPrice) {
- // 计算三重EMA交叉系统
- advancedMA.calculateTripleEMA(priceHistory);
-
- // 计算MACD
- macd.calculate(priceHistory);
-
- // 维护MACD能量柱历史
- updateMacdHistogramHistory();
-
- // 计算RSI
- rsi.calculate(priceHistory);
-
- // 计算KDJ
- kdj.calculate(priceHistory);
-
- // 计算波动率自适应布林带
- calculateAdaptiveBollingerBands();
- }
-
- /**
- * 计算波动率自适应布林带
- */
- private void calculateAdaptiveBollingerBands() {
- // 动态调整布林带的标准差倍数
- BigDecimal atr = calculateATR(priceHistory, 14);
-
- // 根据ATR动态计算标准差倍数
- BigDecimal stdDevMultiplier;
- if (atr.compareTo(new BigDecimal(0.5)) < 0) {
- stdDevMultiplier = new BigDecimal(2);
- } else if (atr.compareTo(new BigDecimal(1)) < 0) {
- stdDevMultiplier = new BigDecimal(2.5);
- } else {
- stdDevMultiplier = new BigDecimal(3);
- }
-
- boll.setK(stdDevMultiplier);
- boll.calculate(priceHistory);
-
- log.debug("ATR: {}, 布林带标准差倍数: {}", atr, stdDevMultiplier);
- }
-
- /**
- * 计算ATR (平均真实范围)
- */
- private BigDecimal calculateATR(List<BigDecimal> prices, int period) {
- if (prices == null || prices.size() < period + 1) {
- return new BigDecimal(0.5); // 默认值
- }
-
- List<BigDecimal> trList = new ArrayList<>();
-
- for (int i = 1; i < prices.size(); i++) {
- BigDecimal high = prices.get(i);
- BigDecimal low = prices.get(i);
- BigDecimal prevClose = prices.get(i - 1);
-
- BigDecimal tr1 = high.subtract(low);
- BigDecimal tr2 = high.subtract(prevClose).abs();
- BigDecimal tr3 = prevClose.subtract(low).abs();
-
- trList.add(tr1.max(tr2).max(tr3));
- }
-
- // 计算ATR
- BigDecimal sum = trList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
- return sum.divide(new BigDecimal(trList.size()), 8, RoundingMode.HALF_UP);
- }
-
- /**
- * 更新MACD能量柱历史
- */
- private void updateMacdHistogramHistory() {
- macdHistogramHistory.add(macd.getMacdBar());
-
- // 限制历史记录数量
- if (macdHistogramHistory.size() > MACD_HISTOGRAM_PERIOD) {
- macdHistogramHistory = macdHistogramHistory.subList(
- macdHistogramHistory.size() - MACD_HISTOGRAM_PERIOD,
- macdHistogramHistory.size());
- }
- }
-
- /**
- * 计算MACD能量柱面积指标(累计过去5根柱体积分)
- */
- private BigDecimal calculateMacdHistogramArea() {
- return macdHistogramHistory.stream()
- .reduce(BigDecimal.ZERO, BigDecimal::add)
- .abs(); // 使用绝对值表示面积
- }
-
- /**
- * 分析技术指标生成交易信号
- */
- private TradeRequestParam analyzeSignal(String accountName, String markPx, String posSide, BigDecimal currentPrice) {
- TradeRequestParam param = createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL);
- param.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- param.setInstId(CoinEnums.HE_YUE.getCode());
- param.setTdMode(CoinEnums.CROSS.getCode());
- param.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode());
-
- // 检查冷静期
- String outStr = getAccountConfig(accountName, CoinEnums.OUT.name());
- if (OrderParamEnums.OUT_YES.getValue().equals(outStr)) {
- log.error("冷静中,不允许下单......");
- param.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return param;
- }
-
- // 检查震荡行情
- if (advancedMA.isUpAndDown()) {
- log.info("处于震荡行情(三线粘合度<{}%),暂停交易", GLUE_THRESHOLD);
- param.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return param;
- }
-
- TradeSignal signal = TradeSignal.NO_SIGNAL;
-
- // 分析多空信号
- signal = analyzeCoreSignal(currentPrice, posSide);
-
- log.info("账户: {}, 价格: {}, 方向: {}, 生成信号: {}",
- accountName, markPx, posSide, signal.getName());
-
- // 设置信号参数
- setSignalParameters(param, signal);
-
- return param;
- }
-
- /**
- * 分析核心技术指标信号
- */
- private TradeSignal analyzeCoreSignal(BigDecimal currentPrice, String posSide) {
- // 计算MACD能量柱面积
- BigDecimal macdArea = calculateMacdHistogramArea();
- BigDecimal prevMacdArea = calculateMacdHistogramAreaPrevious();
-
- // 多头入场条件:当前柱体>0且面积增速>前周期20%
- if (isBullishEntry(macdArea, prevMacdArea)) {
- // 如果当前没有仓位或仓位为空头,则开多
- if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_LONG : TradeSignal.CLOSE_SHORT;
- }
- // 如果当前已经是多头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- // 空头入场条件:当前柱体<0且面积增速>前周期20%
- if (isBearishEntry(macdArea, prevMacdArea)) {
- // 如果当前没有仓位或仓位为多头,则开空
- if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_SHORT : TradeSignal.CLOSE_LONG;
- }
- // 如果当前已经是空头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- // 突破上轨+成交量放大3倍=做空信号
- if (isBollingerUpperBreak(currentPrice) && isVolumeIncreased()) {
- // 如果当前没有仓位或仓位为多头,则开空
- if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_SHORT : TradeSignal.CLOSE_LONG;
- }
- // 如果当前已经是空头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- // 触及下轨+期货资金费率转正=做多信号
- if (isBollingerLowerTouch(currentPrice) && isFundingRatePositive()) {
- // 如果当前没有仓位或仓位为空头,则开多
- if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_LONG : TradeSignal.CLOSE_SHORT;
- }
- // 如果当前已经是多头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- // 空头反转:柱体顶背离+RSI>70区域死叉
- if (isBearishReversal(currentPrice)) {
- // 如果当前没有仓位或仓位为多头,则开空或平多
- if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) {
- return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_SHORT : TradeSignal.CLOSE_LONG;
- }
- // 如果当前已经是空头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- // 多头反转:柱体底背离+RSI<30区域金叉
- if (isBullishReversal(currentPrice)) {
- // 如果当前没有仓位或仓位为空头,则开多或平空
- if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) {
- return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_LONG : TradeSignal.CLOSE_SHORT;
- }
- // 如果当前已经是多头仓位,则保持观望
- return TradeSignal.NO_SIGNAL;
- }
-
- return TradeSignal.NO_SIGNAL;
- }
-
- /**
- * 多头入场条件判断
- */
- private boolean isBullishEntry(BigDecimal currentArea, BigDecimal prevArea) {
- // 当前柱体>0
- boolean currentBarPositive = macd.getMacdBar().compareTo(BigDecimal.ZERO) > 0;
-
- // 面积增速>前周期20%
- boolean areaGrowth = prevArea != null && prevArea.compareTo(BigDecimal.ZERO) > 0 &&
- currentArea.divide(prevArea, 8, RoundingMode.HALF_UP)
- .compareTo(new BigDecimal(1.2)) > 0;
-
- // 三重EMA多头排列
- boolean emaBullish = advancedMA.isBullish();
-
- return currentBarPositive && areaGrowth && emaBullish;
- }
-
- /**
- * 空头入场条件判断
- */
- private boolean isBearishEntry(BigDecimal currentArea, BigDecimal prevArea) {
- // 当前柱体<0
- boolean currentBarNegative = macd.getMacdBar().compareTo(BigDecimal.ZERO) < 0;
-
- // 面积增速>前周期20%
- boolean areaGrowth = prevArea != null && prevArea.compareTo(BigDecimal.ZERO) > 0 &&
- currentArea.divide(prevArea, 8, RoundingMode.HALF_UP)
- .compareTo(new BigDecimal(1.2)) > 0;
-
- // 三重EMA空头排列
- boolean emaBearish = advancedMA.isBearish();
-
- return currentBarNegative && areaGrowth && emaBearish;
- }
-
- /**
- * 突破上轨判断
- */
- private boolean isBollingerUpperBreak(BigDecimal currentPrice) {
- return currentPrice.compareTo(boll.getUpper()) > 0;
- }
-
- /**
- * 触及下轨判断
- */
- private boolean isBollingerLowerTouch(BigDecimal currentPrice) {
- return currentPrice.compareTo(boll.getLower()) < 0;
- }
-
- /**
- * 成交量放大判断(模拟)
- */
- private boolean isVolumeIncreased() {
- // 这里使用价格波动率模拟成交量
- return calculateVolatility(priceHistory, 5)
- .compareTo(calculateVolatility(priceHistory, 20).multiply(VOLUME_MULTIPLIER)) > 0;
- }
-
- /**
- * 期货资金费率转正判断(模拟)
- */
- private boolean isFundingRatePositive() {
- // 这里使用MACD柱状图模拟资金费率
- return macd.getMacdBar().compareTo(BigDecimal.ZERO) > 0;
- }
-
- /**
- * 计算价格波动率
- */
- private BigDecimal calculateVolatility(List<BigDecimal> prices, int period) {
- if (prices.size() < period) {
- return BigDecimal.ZERO;
- }
-
- List<BigDecimal> returns = new ArrayList<>();
- for (int i = 1; i < prices.size(); i++) {
- BigDecimal current = prices.get(i);
- BigDecimal previous = prices.get(i - 1);
- returns.add(current.divide(previous, 8, RoundingMode.HALF_UP).subtract(BigDecimal.ONE));
- }
-
- return calculateStandardDeviation(returns);
- }
-
- /**
- * 计算标准差
- */
- private BigDecimal calculateStandardDeviation(List<BigDecimal> values) {
- if (values.isEmpty()) {
- return BigDecimal.ZERO;
- }
-
- // 计算平均值
- BigDecimal sum = values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
- BigDecimal mean = sum.divide(new BigDecimal(values.size()), 8, RoundingMode.HALF_UP);
-
- // 计算方差
- BigDecimal variance = values.stream()
- .map(val -> val.subtract(mean).pow(2))
- .reduce(BigDecimal.ZERO, BigDecimal::add)
- .divide(new BigDecimal(values.size()), 8, RoundingMode.HALF_UP);
-
- // 计算标准差
- return sqrt(variance);
- }
-
- /**
- * 计算平方根
- */
- private BigDecimal sqrt(BigDecimal value) {
- return new BigDecimal(Math.sqrt(value.doubleValue()));
- }
-
- /**
- * 空头反转判断
- */
- private boolean isBearishReversal(BigDecimal currentPrice) {
- // 柱体顶背离
- boolean topDivergence = isMacdTopDivergence(currentPrice);
-
- // RSI>70区域死叉
- boolean rsiOverbought = rsi.getRsi().compareTo(new BigDecimal(70)) > 0;
- boolean kdjDeathCross = kdj.isDeathCross();
-
- return topDivergence && rsiOverbought && kdjDeathCross;
- }
-
- /**
- * 多头反转判断
- */
- private boolean isBullishReversal(BigDecimal currentPrice) {
- // 柱体底背离
- boolean bottomDivergence = isMacdBottomDivergence(currentPrice);
-
- // RSI<30区域金叉
- boolean rsiOversold = rsi.getRsi().compareTo(new BigDecimal(30)) < 0;
- boolean kdjGoldenCross = kdj.isGoldenCross();
-
- return bottomDivergence && rsiOversold && kdjGoldenCross;
- }
-
- /**
- * 判断MACD顶背离
- */
- private boolean isMacdTopDivergence(BigDecimal currentPrice) {
- // 简化的顶背离判断:价格创新高但MACD未创新高
- if (priceHistory.size() < 2) {
- return false;
- }
-
- BigDecimal previousPrice = priceHistory.get(priceHistory.size() - 2);
- return currentPrice.compareTo(previousPrice) > 0 &&
- macd.getMacdBar().compareTo(prevDea) < 0;
- }
-
- /**
- * 判断MACD底背离
- */
- private boolean isMacdBottomDivergence(BigDecimal currentPrice) {
- // 简化的底背离判断:价格创新低但MACD未创新低
- if (priceHistory.size() < 2) {
- return false;
- }
-
- BigDecimal previousPrice = priceHistory.get(priceHistory.size() - 2);
- return currentPrice.compareTo(previousPrice) < 0 &&
- macd.getMacdBar().compareTo(prevDea) > 0;
- }
-
- /**
- * 计算前一期MACD能量柱面积
- */
- private BigDecimal calculateMacdHistogramAreaPrevious() {
- if (macdHistogramHistory.size() < 2) {
- return BigDecimal.ZERO;
- }
-
- List<BigDecimal> prevHistory = macdHistogramHistory.subList(
- 0, macdHistogramHistory.size() - 1);
-
- return prevHistory.stream()
- .reduce(BigDecimal.ZERO, BigDecimal::add)
- .abs();
- }
-
- /**
- * 设置信号参数
- */
- private void setSignalParameters(TradeRequestParam param, TradeSignal signal) {
- String side = null;
-
- switch (signal) {
- case BUY:
- side = CoinEnums.SIDE_BUY.getCode();
- param.setPosSide(CoinEnums.POSSIDE_LONG.getCode());
- break;
- case SELL:
- side = CoinEnums.SIDE_SELL.getCode();
- param.setPosSide(CoinEnums.POSSIDE_SHORT.getCode());
- break;
- case OPEN_LONG:
- side = CoinEnums.SIDE_BUY.getCode();
- param.setPosSide(CoinEnums.POSSIDE_LONG.getCode());
- break;
- case CLOSE_LONG:
- side = CoinEnums.SIDE_SELL.getCode();
- break;
- case OPEN_SHORT:
- side = CoinEnums.SIDE_SELL.getCode();
- param.setPosSide(CoinEnums.POSSIDE_SHORT.getCode());
- break;
- case CLOSE_SHORT:
- side = CoinEnums.SIDE_BUY.getCode();
- break;
- case STOP_LOSS:
- // 止损操作
- side = CoinEnums.POSSIDE_LONG.getCode().equals(param.getPosSide()) ?
- CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode();
- break;
- default:
- param.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- return;
- }
-
- param.setSide(side);
- log.info("设置交易方向: {}, 仓位方向: {}", side, param.getPosSide());
- }
-
- /**
- * 更新历史指标值
- */
- private void updateHistoricalIndicatorValues() {
- prevEma9 = advancedMA.getEma9();
- prevEma21 = advancedMA.getEma21();
- prevEma55 = advancedMA.getEma55();
- prevDif = macd.getDif();
- prevDea = macd.getDea();
- prevK = kdj.getK();
- prevD = kdj.getD();
- prevJ = kdj.getJ();
- }
-
- /**
- * 获取账户配置
- */
- private String getAccountConfig(String accountName, String key) {
- // 模拟获取账户配置
- return OrderParamEnums.OUT_NO.getValue();
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/CoreTechnicalStrategyUsageGuide.md b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/CoreTechnicalStrategyUsageGuide.md
deleted file mode 100644
index 0e56433..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/CoreTechnicalStrategyUsageGuide.md
+++ /dev/null
@@ -1,198 +0,0 @@
-# CoreTechnicalStrategy 使用指南
-
-## 1. 概述
-CoreTechnicalStrategy 是一个综合技术指标策略类,整合了以下核心技术指标:
-- 三重EMA交叉系统(9/21/55周期)
-- 波动率自适应布林带
-- MACD能量柱分级策略
-
-## 2. 类结构
-
-### 2.1 AdvancedMA 类
-用于计算三重EMA交叉系统的指标。
-
-**主要方法:**
-- `calculateTripleEMA(List<BigDecimal> prices)`: 计算9EMA、21EMA、55EMA
-- `isBullish排列()`: 判断是否多头排列(9EMA>21EMA>55EMA)
-- `isBearish排列()`: 判断是否空头排列(9EMA<21EMA<55EMA)
-- `calculate粘合度()`: 计算三线粘合度
-- `is震荡行情()`: 判断是否处于震荡行情(粘合度<2%)
-
-### 2.2 CoreTechnicalStrategy 类
-综合所有技术指标生成交易信号的策略类。
-
-**主要方法:**
-- `initialize()`: 初始化策略
-- `updatePrices(List<BigDecimal> prices)`: 更新价格数据
-- `getSignal(String accountName, String markPx, String posSide)`: 获取交易信号
-
-## 3. 使用步骤
-
-### 3.1 初始化策略
-```java
-// 创建策略实例
-CoreTechnicalStrategy strategy = new CoreTechnicalStrategy();
-
-// 初始化策略
-strategy.initialize();
-```
-
-### 3.2 更新价格数据
-```java
-// 准备价格数据列表
-List<BigDecimal> prices = new ArrayList<>();
-prices.add(new BigDecimal(30000));
-prices.add(new BigDecimal(30500));
-prices.add(new BigDecimal(31000));
-// 添加更多价格数据...
-
-// 更新价格数据
-strategy.updatePrices(prices);
-```
-
-### 3.3 获取交易信号
-```java
-// 调用getSignal方法获取交易信号
-TradeRequestParam param = strategy.getSignal(
- "account1", // 账户名称
- "31500", // 当前标记价格
- "long" // 当前仓位方向("long"或"short")
-);
-
-// 获取交易方向
-String side = param.getSide(); // "buy"或"sell"
-String tradeType = param.getTradeType(); // "yes"或"no"
-```
-
-## 4. 参数说明
-
-### 4.1 getSignal 方法参数
-
-| 参数名 | 类型 | 说明 | 示例 |
-|-------|------|------|------|
-| accountName | String | 账户名称,用于日志记录和配置获取 | "account1", "myAccount" |
-| markPx | String | 当前标记价格,作为交易决策的基础价格 | "31500", "32000.5" |
-| posSide | String | 当前仓位方向,决定多空信号的生成逻辑 | "long"(多头), "short"(空头) |
-
-### 4.2 返回值 TradeRequestParam 说明
-
-| 属性名 | 类型 | 说明 |
-|-------|------|------|
-| accountName | String | 账户名称 |
-| markPx | String | 当前标记价格 |
-| posSide | String | 仓位方向 |
-| side | String | 交易方向:"buy"(买入/做多)或"sell"(卖出/做空) |
-| tradeType | String | 交易类型:"yes"(执行交易)或"no"(不执行交易) |
-| instId | String | 交易对ID |
-| tdMode | String | 交易模式 |
-| ordType | String | 订单类型 |
-
-## 5. 核心指标逻辑
-
-### 5.1 三重EMA交叉系统
-- **多头条件**:9EMA > 21EMA > 55EMA
-- **空头条件**:9EMA < 21EMA < 55EMA
-- **震荡过滤**:三线粘合度 < 2% 时暂停交易
-
-### 5.2 波动率自适应布林带
-- **动态通道宽度**:标准差倍数根据ATR调整
-- **做空信号**:突破上轨 + 成交量放大3倍
-- **做多信号**:触及下轨 + 期货资金费率转正
-
-### 5.3 MACD能量柱分级策略
-- **能量柱面积**:累计过去5根柱体积分
-- **多头入场**:当前柱体 > 0 且面积增速 > 前周期20%
-- **空头反转**:柱体顶背离 + RSI > 70区域死叉
-
-## 6. 示例代码
-
-```java
-public class StrategyExample {
- public static void main(String[] args) {
- // 初始化策略
- CoreTechnicalStrategy strategy = new CoreTechnicalStrategy();
- strategy.initialize();
-
- // 准备历史价格数据
- List<BigDecimal> historicalPrices = new ArrayList<>();
- for (int i = 0; i < 100; i++) {
- // 模拟价格数据
- BigDecimal price = new BigDecimal(30000 + i * 100 + Math.random() * 500);
- historicalPrices.add(price);
- }
-
- // 更新价格数据
- strategy.updatePrices(historicalPrices);
-
- // 获取当前价格
- String currentPrice = "35000";
-
- // 获取多头信号
- TradeRequestParam longSignal = strategy.getSignal("myAccount", currentPrice, "long");
- System.out.println("多头信号: " + longSignal.getSide() + ", 交易类型: " + longSignal.getTradeType());
-
- // 获取空头信号
- TradeRequestParam shortSignal = strategy.getSignal("myAccount", currentPrice, "short");
- System.out.println("空头信号: " + shortSignal.getSide() + ", 交易类型: " + shortSignal.getTradeType());
- }
-}
-```
-
-## 7. 注意事项
-
-1. **价格数据长度**:建议至少提供55个以上的价格数据点,以确保所有指标都能正确计算
-2. **初始化顺序**:必须先调用`initialize()`方法,再调用`updatePrices()`和`getSignal()`
-3. **仓位方向**:传入的`posSide`参数会影响信号生成逻辑,请确保传入正确的当前仓位方向
-4. **日志记录**:策略会输出详细的日志信息,可通过日志级别控制输出内容
-5. **震荡过滤**:当处于震荡行情时,`tradeType`会返回"no",建议暂停交易
-
-## 8. 错误处理
-
-策略内部包含完善的错误处理机制:
-- 价格数据为空或无效时,会返回`NO_SIGNAL`
-- 计算过程中发生异常时,会捕获并记录日志,返回`NO_SIGNAL`
-- 冷静期内会返回`tradeType="no"`
-- 震荡行情会返回`tradeType="no"`
-
-## 9. 扩展与定制
-
-### 9.1 修改指标参数
-可以在`CoreTechnicalStrategy`类中修改以下常量来调整策略参数:
-
-```java
-// MACD能量柱计算周期
-private static final int MACD_HISTOGRAM_PERIOD = 5;
-
-// 成交量放大倍数
-private static final BigDecimal VOLUME_MULTIPLIER = new BigDecimal(3);
-
-// 三线粘合度阈值(%)
-private static final BigDecimal GLUE_THRESHOLD = new BigDecimal(2);
-```
-
-### 9.2 自定义信号逻辑
-可以重写`analyzeCoreSignal`方法来自定义信号生成逻辑:
-
-```java
-@Override
-protected TradeSignal analyzeCoreSignal(BigDecimal currentPrice) {
- // 自定义信号逻辑
- // ...
-}
-```
-
-## 10. 整合到现有系统
-
-要将CoreTechnicalStrategy整合到现有系统中,只需将其替换或补充现有的策略类即可:
-
-```java
-// 在OkxWebSocketClientManager或其他适当位置
-CoreTechnicalStrategy coreStrategy = new CoreTechnicalStrategy();
-coreStrategy.initialize();
-
-// 在价格更新时
-coreStrategy.updatePrices(priceList);
-
-// 在需要交易信号时
-TradeRequestParam signal = coreStrategy.getSignal(accountName, markPx, posSide);
-```
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/TechnicalIndicatorStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/TechnicalIndicatorStrategy.java
deleted file mode 100644
index 65b4d95..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/TechnicalIndicatorStrategy.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator.strategy;
-
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * 技术指标策略接口,定义技术指标策略的基本方法
- */
-public interface TechnicalIndicatorStrategy {
-
- /**
- * 初始化策略
- */
- void initialize();
-
- /**
- * 更新价格数据
- * @param prices 价格列表
- */
- void updatePrices(List<BigDecimal> prices);
-
- /**
- * 获取交易信号
- * @param accountName 账户名称
- * @param markPx 当前标记价格
- * @param posSide 仓位方向
- * @return 交易请求参数,包含交易信号和相关信息
- */
- TradeRequestParam getSignal(String accountName, String markPx, String posSide);
-
- /**
- * 获取策略名称
- * @return 策略名称
- */
- String getStrategyName();
-
- /**
- * 判断策略是否有效
- * @return 是否有效
- */
- boolean isValid();
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/TradeSignal.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/TradeSignal.java
deleted file mode 100644
index e1c05da..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/strategy/TradeSignal.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.indicator.strategy;
-
-import lombok.Getter;
-
-/**
- * 交易信号枚举
- */
-@Getter
-public enum TradeSignal {
-
- /** 无信号,保持观望 */
- NO_SIGNAL("NO_SIGNAL", "无信号"),
-
- /** 买入信号 */
- BUY("BUY", "买入"),
-
- /** 卖出信号 */
- SELL("SELL", "卖出"),
-
- /** 开多信号 */
- OPEN_LONG("OPEN_LONG", "开多"),
-
- /** 平多信号 */
- CLOSE_LONG("CLOSE_LONG", "平多"),
-
- /** 开空信号 */
- OPEN_SHORT("OPEN_SHORT", "开空"),
-
- /** 平空信号 */
- CLOSE_SHORT("CLOSE_SHORT", "平空"),
-
- /** 止损信号 */
- STOP_LOSS("STOP_LOSS", "止损"),
-
- /** 止盈信号 */
- TAKE_PROFIT("TAKE_PROFIT", "止盈");
-
- private final String value;
- private final String name;
-
- TradeSignal(String value, String name) {
- this.value = value;
- this.name = name;
- }
-
- public static TradeSignal fromValue(String value) {
- for (TradeSignal signal : values()) {
- if (signal.getValue().equals(value)) {
- return signal;
- }
- }
- return NO_SIGNAL;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/jiaoyi/IMQService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/jiaoyi/IMQService.java
deleted file mode 100644
index 411481c..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/jiaoyi/IMQService.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.jiaoyi;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestBuy;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestSell;
-
-public interface IMQService {
-
-
-
- /**
- * 消费买入消息
- * @param returnVo
- */
- void operationBuyMsg(TradeRequestBuy returnVo);
-
-
- /**
- * 消费卖出消息
- * @param returnVo
- */
- void operationSellMsg(TradeRequestSell returnVo);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/jiaoyi/IMQServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/jiaoyi/IMQServiceImpl.java
deleted file mode 100644
index 4ac6153..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/jiaoyi/IMQServiceImpl.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.jiaoyi;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.json.JSONUtil;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.MallUtils;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.enumerates.TradeTypeEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeEventEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeEventRunner;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestBuy;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestSell;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.VerifyAccountFactory;
-import com.xcong.excoin.modules.okxNewPrice.zhanghu.IApiMessageService;
-import com.xcong.excoin.modules.okxNewPrice.zhanghu.ZhangHuEnum;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-import java.util.LinkedHashMap;
-
-/**
- * @author Administrator
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class IMQServiceImpl implements IMQService{
-
- private final IApiMessageService apiMessageService;
-
- private final VerifyAccountFactory verifyAccountFactory;
- @Override
- public void operationBuyMsg(TradeRequestBuy returnVo) {
-
- log.info("买入入参:{}", JSON.toJSONString(returnVo));
- /**
- * 1、获取用户的策略信息
- * 2、quant_operate_recode 记录表新增一条记录,finish_status 为1.未完成
- * 3、发起OKX接口调用
- */
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- if(ObjectUtil.isEmpty(quantApiMessage)){
- return;
- }
-
- OKXAccount okxAccount = (OKXAccount) verifyAccountFactory.getAccountMap()
- .get(quantApiMessage.getExchange())
- .initAccount(quantApiMessage);
- if(ObjectUtil.isEmpty(okxAccount)){
- return;
- }
-
- LinkedHashMap<String, Object> requestParam = new LinkedHashMap<>();
- requestParam.put("instId", returnVo.getInstId()+"-SWAP");
- /**
- * 订单方向
- * buy:买, sell:卖
- */
- requestParam.put("side", TradeTypeEnum.BUY.getValue());
- /**
- * 订单类型
- * market:市价单
- * limit:限价单
- * post_only:只做maker单
- * fok:全部成交或立即取消
- * ioc:立即成交并取消剩余
- * optimal_limit_ioc:市价委托立即成交并取消剩余(仅适用交割、永续)
- * mmp:做市商保护(仅适用于组合保证金账户模式下的期权订单)
- * mmp_and_post_only:做市商保护且只做maker单(仅适用于组合保证金账户模式下的期权订单)
- */
- String type = (BigDecimal.ZERO.compareTo(new BigDecimal(returnVo.getLimitPrice())) == 0) ? TradeTypeEnum.MARKET.getValue() : TradeTypeEnum.LIMIT.getValue();
- requestParam.put("ordType", type);
- if (TradeTypeEnum.LIMIT.getValue().equals(type)) {
- requestParam.put("px", returnVo.getLimitPrice());
- requestParam.put("ordType", TradeTypeEnum.LIMIT.getValue());
- }
- /**
- * 持仓方向
- * 在开平仓模式下必填,且仅可选择 long 或 short。 仅适用交割、永续。
- */
- String positionSide = (TradeTypeEnum.LONG.getCode() == returnVo.getPositionSide()) ? TradeTypeEnum.LONG.getValue() : TradeTypeEnum.SHORT.getValue();
- requestParam.put("posSide", positionSide);
- /**
- * 交易模式
- * 保证金模式:isolated:逐仓 ;cross:全仓
- * 非保证金模式:cash:非保证金
- * spot_isolated:现货逐仓(仅适用于现货带单) ,现货带单时,tdMode 的值需要指定为spot_isolated
- */
- String tdMode = (TradeTypeEnum.ISOLATED.getCode() == returnVo.getTdMode()) ? TradeTypeEnum.ISOLATED.getValue() : TradeTypeEnum.CROSS.getValue();
- requestParam.put("tdMode", tdMode);
- /**
- * 委托数量
- */
- requestParam.put("sz", returnVo.getTradeCnt());
- /**
- * 客户自定义订单ID
- * 字母(区分大小写)与数字的组合,可以是纯字母、纯数字且长度要在1-32位之间。
- */
- String clOrdId = MallUtils.getOrderNum();
- requestParam.put("clOrdId", clOrdId);
-
- String placeOrderRspOkxRestResponse = TradeEventRunner.runTradeEvent(TradeEventEnum.TRADE_BUY.getEventPoint(),requestParam,okxAccount);
- log.info("下买单结果成功:{}", placeOrderRspOkxRestResponse);
- log.info("消费成功:{}", JSONUtil.parseObj(returnVo));
- }
-
- @Override
- public void operationSellMsg(TradeRequestSell returnVo) {
- /**
- * 1、获取用户的策略信息
- * 2、quant_operate_recode 记录表新增一条记录,finish_status 为1.未完成
- * 3、发起OKX接口调用
- */
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- if(ObjectUtil.isEmpty(quantApiMessage)){
- return;
- }
-
- OKXAccount okxAccount = (OKXAccount) verifyAccountFactory.getAccountMap()
- .get(quantApiMessage.getExchange())
- .initAccount(quantApiMessage);
- if(ObjectUtil.isEmpty(okxAccount)){
- return;
- }
- LinkedHashMap<String, Object> requestParam = new LinkedHashMap<>();
-
- requestParam.put("instId", returnVo.getInstId()+"-SWAP");
- /**
- * 订单方向
- * buy:买, sell:卖
- */
- requestParam.put("side", TradeTypeEnum.SELL.getValue());
- /**
- * 订单类型
- * market:市价单
- * limit:限价单
- * post_only:只做maker单
- * fok:全部成交或立即取消
- * ioc:立即成交并取消剩余
- * optimal_limit_ioc:市价委托立即成交并取消剩余(仅适用交割、永续)
- * mmp:做市商保护(仅适用于组合保证金账户模式下的期权订单)
- * mmp_and_post_only:做市商保护且只做maker单(仅适用于组合保证金账户模式下的期权订单)
- */
- String type = (BigDecimal.ZERO.compareTo(new BigDecimal(returnVo.getLimitPrice())) == 0) ? TradeTypeEnum.MARKET.getValue() : TradeTypeEnum.LIMIT.getValue();
- requestParam.put("ordType", type);
- if (TradeTypeEnum.LIMIT.getValue().equals(type)) {
- requestParam.put("px", returnVo.getLimitPrice());
- requestParam.put("ordType", TradeTypeEnum.LIMIT.getValue());
- }
- /**
- * 持仓方向
- * 在开平仓模式下必填,且仅可选择 long 或 short。 仅适用交割、永续。
- */
- String positionSide = (TradeTypeEnum.LONG.getCode() == returnVo.getPositionSide()) ? TradeTypeEnum.LONG.getValue() : TradeTypeEnum.SHORT.getValue();
- requestParam.put("posSide", positionSide);
- /**
- * 交易模式
- * 保证金模式:isolated:逐仓 ;cross:全仓
- * 非保证金模式:cash:非保证金
- * spot_isolated:现货逐仓(仅适用于现货带单) ,现货带单时,tdMode 的值需要指定为spot_isolated
- */
- String tdMode = (TradeTypeEnum.ISOLATED.getCode() == returnVo.getTdMode()) ? TradeTypeEnum.ISOLATED.getValue() : TradeTypeEnum.CROSS.getValue();
- requestParam.put("tdMode", tdMode);
- /**
- * 委托数量
- */
- requestParam.put("sz", returnVo.getTradeCnt());
- /**
- * 客户自定义订单ID
- * 字母(区分大小写)与数字的组合,可以是纯字母、纯数字且长度要在1-32位之间。
- */
- String clOrdId = MallUtils.getOrderNum();
- requestParam.put("clOrdId", clOrdId);
-
-
- String placeOrderRspOkxRestResponse = TradeEventRunner.runTradeEvent(TradeEventEnum.TRADE_SELL.getEventPoint(), requestParam, okxAccount);
-
- String code = JSON.parseObject(placeOrderRspOkxRestResponse).get("code").toString();
- if("1".equals(code)){
- String data = JSON.parseObject(placeOrderRspOkxRestResponse).get("data").toString();
-
- JSONArray jsonArray = JSON.parseArray(data);
- JSONObject jsonObject = jsonArray.getJSONObject(0);
-
- String sCode = jsonObject.getString("sCode");
- if("51169".equals(sCode)){
- log.warn("平仓下单返回结果-失败:{}", data);
- }
- }
- log.info("平仓下单返回结果:{}", placeOrderRspOkxRestResponse);
- log.info("消费成功:{}", JSONUtil.parseObj(returnVo));
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/AccountWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/AccountWs.java
deleted file mode 100644
index 81188a8..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/AccountWs.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs;
-
-import cn.hutool.json.JSONUtil;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.MallUtils;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import io.micrometer.core.instrument.util.JsonUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 账户 WebSocket 处理类,用于订阅 OKX 的账户频道并处理账户信息推送。
- * 包含账户资金状态判断、计算下单保证金及保存到 Redis 的逻辑。
- *
- * @author Administrator
- */
-@Slf4j
-public class AccountWs {
-
- // 使用双层Map,第一层key为账号名称,第二层key为数据key
- private static final Map<String, Map<String, String>> ACCOUNTWSMAP = new ConcurrentHashMap<>();
-
- // 获取指定账号的Map,如果不存在则创建
- public static Map<String, String> getAccountMap(String accountName) {
- return ACCOUNTWSMAP.computeIfAbsent(accountName, k -> new ConcurrentHashMap<>());
- }
- /**
- * 账户频道名称常量
- */
- public static final String ACCOUNTWS_CHANNEL = "account";
-
- /**
- * 订阅账户频道
- *
- * @param webSocketClient WebSocket 客户端实例
- * @param option 请求选项(如 unsubscribe 或 subscribe)
- */
- public static void subscribeAccountChannel(WebSocketClient webSocketClient, String option) {
- try {
- JSONArray argsArray = new JSONArray();
- JSONObject args = new JSONObject();
- args.put("channel", ACCOUNTWS_CHANNEL);
- args.put("ccy", CoinEnums.USDT.getCode());
- argsArray.add(args);
-
- String connId = MallUtils.getOrderNum(ACCOUNTWS_CHANNEL);
- JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, option, argsArray);
- webSocketClient.send(jsonObject.toJSONString());
-// log.info("发送账户频道:{}", option);
- } catch (Exception e) {
- log.error("订阅账户频道构建失败", e);
- }
- }
-
- public static void initEvent(JSONObject response, String accountName) {
-// log.info("订阅成功: {}", response.getJSONObject("arg"));
- JSONObject arg = response.getJSONObject("arg");
- initParam(arg, accountName);
- }
-
- /**
- * 处理账户频道推送的数据
- *
- * @param response 推送的 JSON 数据对象
- * @param accountName 账号名称
- */
- public static void handleEvent(JSONObject response, String accountName) {
-
-
-// log.info("开始执行AccountWs......{}",ACCOUNTWS_CHANNEL);
- try {
- JSONArray dataArray = response.getJSONArray("data");
- if (dataArray == null || dataArray.isEmpty()) {
- log.warn("账户频道数据为空");
- return;
- }
-
- for (int i = 0; i < dataArray.size(); i++) {
- try {
- JSONObject accountData = dataArray.getJSONObject(i);
- JSONArray detailsArray = accountData.getJSONArray("details");
- if (detailsArray == null || detailsArray.isEmpty()) {
- log.warn("账户频道{}数据为空",CoinEnums.USDT.getCode());
- continue;
- }
-
- for (int j = 0; j < detailsArray.size(); j++) {
- JSONObject detail = detailsArray.getJSONObject(j);
- initParam(detail, accountName);
-
- Map<String, String> accountMap = getAccountMap(accountName);
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.READY_STATE.name(), CoinEnums.READY_STATE_YES.getCode());
- }
- } catch (Exception innerEx) {
- log.warn("处理账户频道数据失败", innerEx);
- }
- }
- } catch (Exception e) {
- log.error("处理账户频道推送数据失败", e);
- }
- }
-
-
- public static final String ccyKey = "ccy";
- public static final String availBalKey = "availBal";
- public static final String cashBalKey = "cashBal";
- public static final String eqKey = "eq";
- public static final String uplKey = "upl";
- public static final String imrKey = "imr";
- private static void initParam(JSONObject detail, String accountName) {
- Map<String, String> accountMap = getAccountMap(accountName);
-
- String ccy = WsMapBuild.parseStringSafe( detail.getString(ccyKey));
- WsMapBuild.saveStringToMap(accountMap, ccyKey, ccy);
-
- String availBal = WsMapBuild.parseStringSafe(detail.getString(availBalKey));
- WsMapBuild.saveStringToMap(accountMap, availBalKey, availBal);
-
- String cashBal = WsMapBuild.parseStringSafe(detail.getString(cashBalKey));
- WsMapBuild.saveStringToMap(accountMap, cashBalKey, cashBal);
-
- String eq = WsMapBuild.parseStringSafe(detail.getString(eqKey));
- WsMapBuild.saveStringToMap(accountMap, eqKey, eq);
-
- String upl = WsMapBuild.parseStringSafe(detail.getString(uplKey));
- WsMapBuild.saveStringToMap(accountMap, uplKey, upl);
-
- String imr = WsMapBuild.parseStringSafe(detail.getString(imrKey));
- WsMapBuild.saveStringToMap(accountMap, imrKey, imr);
- BigDecimal cashBalDecimal = WsMapBuild.parseBigDecimalSafe(cashBal);
- // 根据可用余额计算下单总保证金
- String total_order_usdtpecent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.TOTAL_ORDER_USDTPECENT.name());
- BigDecimal total_order_usdt_factor = WsMapBuild.parseBigDecimalSafe(total_order_usdtpecent);
- BigDecimal totalOrderUsdt = cashBalDecimal.multiply(total_order_usdt_factor).setScale(2, RoundingMode.DOWN);
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.TOTAL_ORDER_USDT.name(), String.valueOf(totalOrderUsdt));
-
- /**
- * 当前账户未满仓,并且账户余额不为0,才更新为已就绪
- */
- BigDecimal imrDecimal = WsMapBuild.parseBigDecimalSafe(imr);
- if (BigDecimal.ZERO.compareTo(cashBalDecimal) < 0 && imrDecimal.compareTo(totalOrderUsdt) < 0){
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.READY_STATE.name(), CoinEnums.READY_STATE_YES.getCode());
- }
-
-// log.info(
-// "{}: 账户详情-币种: {}, 可用余额: {}, 现金余额: {}, 余额: {}, 全仓未实现盈亏: {}, 下单总保证金: {},已使用保证金:{}",
-// accountName, ccy, availBal, cashBal, eq, upl, totalOrderUsdt,imr
-// );
- }
-}
-
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/BalanceAndPositionWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/BalanceAndPositionWs.java
deleted file mode 100644
index 9667283..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/BalanceAndPositionWs.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.MallUtils;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-/**
- * @author Administrator
- */
-@Slf4j
-public class BalanceAndPositionWs {
-
- public static final String CHANNEL_NAME = "balance_and_position";
- private static final String LOG_PREFIX = "账户余额和持仓频道";
-
- public static void subscribeBalanceAndPositionChannel(WebSocketClient webSocketClient, String option) {
- try {
- JSONArray argsArray = new JSONArray();
- JSONObject args = new JSONObject();
- args.put("channel", CHANNEL_NAME);
- argsArray.add(args);
-
- String connId = MallUtils.getOrderNum("bap");
- JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, option, argsArray);
- webSocketClient.send(jsonObject.toJSONString());
- log.info("账户余额和持仓频道订阅成功: {}", LOG_PREFIX, option);
- } catch (Exception e) {
- log.error("账户余额和持仓频道订阅构建失败", LOG_PREFIX, e);
- }
- }
-
- public static void handleEvent(JSONObject response) {
-
- log.info("开始执行BalanceAndPositionWs......");
- try {
- JSONArray dataArray = response.getJSONArray("data");
- if (dataArray == null || dataArray.isEmpty()) {
- log.warn("{}数据为空", LOG_PREFIX);
- return;
- }
-
- JSONObject firstData = dataArray.getJSONObject(0);
- processBalData(firstData);
- processPosData(firstData);
- } catch (Exception e) {
- log.error("{}推送数据处理失败", LOG_PREFIX, e);
- }
- }
-
- private static void processBalData(JSONObject dataObject) {
- JSONArray balDataArray = dataObject.getJSONArray("balData");
- if (balDataArray == null || balDataArray.isEmpty()) {
- return;
- }
-
- for (int i = 0; i < balDataArray.size(); i++) {
- JSONObject balData = balDataArray.getJSONObject(i);
- if (!balData.containsKey("ccy") || !balData.containsKey("cashBal") || !balData.containsKey("uTime")) {
- continue;
- }
-
- String ccy = balData.getString("ccy");
- String cashBal = balData.getString("cashBal");
- String uTime = balData.getString("uTime");
-
- log.info("币种: {}, 余额: {}, 更新时间: {}", ccy, cashBal, uTime);
- }
- }
-
- private static void processPosData(JSONObject dataObject) {
- JSONArray posDataArray = dataObject.getJSONArray("posData");
- if (posDataArray == null || posDataArray.isEmpty()) {
- return;
- }
-
- for (int i = 0; i < posDataArray.size(); i++) {
- JSONObject posData = posDataArray.getJSONObject(i);
- if (!posData.containsKey("posId") || !posData.containsKey("instId")
- || !posData.containsKey("instType") || !posData.containsKey("posSide")
- || !posData.containsKey("pos") || !posData.containsKey("avgPx")
- || !posData.containsKey("ccy")) {
- continue;
- }
-
- String posId = posData.getString("posId");
- String instId = posData.getString("instId");
- String instType = posData.getString("instType");
- String posSide = posData.getString("posSide");
- String pos = posData.getString("pos");
- String avgPx = posData.getString("avgPx");
- String ccy = posData.getString("ccy");
-
- log.info("持仓ID: {}, 产品ID: {}, 类型: {}, 方向: {}, 数量: {}, 平均价: {}, 币种: {}",
- posId, instId, instType, posSide, pos, avgPx, ccy);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/InstrumentsWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/InstrumentsWs.java
deleted file mode 100644
index 334443e..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/InstrumentsWs.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs;
-
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * @author Administrator
- */
-@Slf4j
-public class InstrumentsWs {
-
- public static final Map<String, Map<String, String>> INSTRUMENTSWSMAP = new ConcurrentHashMap<>();
-
- public static final String INSTRUMENTSWS_CHANNEL = "instruments";
-
- public static Map<String, String> getAccountMap(String accountName) {
- return INSTRUMENTSWSMAP.computeIfAbsent(accountName, k -> new ConcurrentHashMap<>());
- }
-
- public static void handleEvent(String accountName) {
-// log.info("开始执行InstrumentsWs......");
-
- Map<String, String> accountMap = getAccountMap(accountName);
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.HE_YUE.name(), CoinEnums.HE_YUE.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.CTVAL.name(), CoinEnums.CTVAL.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.TICKSZ.name(), CoinEnums.TICKSZ.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.MINSZ.name(), CoinEnums.MINSZ.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.OUT.name(), OrderParamEnums.OUT_NO.getValue());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.LEVERAGE.name(), CoinEnums.LEVERAGE.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.BUY_CNT.name(), CoinEnums.BUY_CNT.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.BUY_CNT_INIT.name(), CoinEnums.BUY_CNT_INIT.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.BUY_CNT_TIME.name(), CoinEnums.BUY_CNT_TIME.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.ZHI_SUN.name(), CoinEnums.ZHI_SUN.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.KANG_CANG.name(), CoinEnums.KANG_CANG.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.PING_CANG_SHOUYI.name(), CoinEnums.PING_CANG_SHOUYI.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.TOTAL_ORDER_USDTPECENT.name(), CoinEnums.TOTAL_ORDER_USDTPECENT.getCode());
- WsMapBuild.saveStringToMap(accountMap, CoinEnums.CONTRACTMULTIPLIER.name(), CoinEnums.CONTRACTMULTIPLIER.getCode());
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/LoginWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/LoginWs.java
deleted file mode 100644
index eb3e416..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/LoginWs.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.ExchangeInfoEnum;
-import com.xcong.excoin.modules.okxNewPrice.utils.SignUtils;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-/**
- * @author Administrator
- */
-@Slf4j
-public class LoginWs {
- public static void websocketLogin(WebSocketClient webSocketClient, ExchangeInfoEnum account) {
-
-// log.info("开始执行LoginWs......");
- try {
-
- JSONArray argsArray = new JSONArray();
- JSONObject loginArgs = new JSONObject();
- // 获取登录凭证信息(需要从配置或Redis中获取)
- String apiKey = account.getApiKey();
- String passphrase = account.getPassphrase();
- String timestamp = String.valueOf(System.currentTimeMillis() /1000);
- String sign = SignUtils.signWebsocket(timestamp, account.getSecretKey());
-
- loginArgs.put("apiKey", apiKey);
- loginArgs.put("passphrase", passphrase);
- loginArgs.put("timestamp", timestamp);
- loginArgs.put("sign", sign);
- argsArray.add(loginArgs);
-
- String option = "login";
- JSONObject login = WsParamBuild.buildJsonObject(null,option, argsArray);
- webSocketClient.send(login.toJSONString());
- log.info("发送登录:{}",option);
- } catch (Exception e) {
- log.error("WebSocket登录请求构建失败", e);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java
deleted file mode 100644
index 883a2ca..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java
+++ /dev/null
@@ -1,254 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs;
-
-import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.MallUtils;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * @author Administrator
- */
-@Slf4j
-public class OrderInfoWs {
-
- // 使用双层Map,第一层key为账号名称,第二层key为数据key
- public static final Map<String, Map<String, String>> ORDERINFOWSMAP = new ConcurrentHashMap<>();
-
- // 获取指定账号的Map,如果不存在则创建
- public static Map<String, String> getAccountMap(String accountName) {
- return ORDERINFOWSMAP.computeIfAbsent(accountName, k -> new ConcurrentHashMap<>());
- }
-
- public static final String ORDERINFOWS_CHANNEL = "orders";
-
- public static void subscribeOrderInfoChannel(WebSocketClient webSocketClient, String option) {
- try {
- JSONArray argsArray = new JSONArray();
- JSONObject args = new JSONObject();
- args.put("channel", ORDERINFOWS_CHANNEL);
- args.put("instType", CoinEnums.INSTTYPE_SWAP.getCode());
- args.put("instId", CoinEnums.HE_YUE.getCode());
- argsArray.add(args);
-
- String connId = MallUtils.getOrderNum(ORDERINFOWS_CHANNEL);
- JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, option, argsArray);
- webSocketClient.send(jsonObject.toJSONString());
-// log.info("发送订单频道频道:{}", option);
- } catch (Exception e) {
- log.error("订阅订单频道构建失败", e);
- }
- }
-
- public static void initEvent(JSONObject response, String accountName) {
-// log.info("订阅成功: {}", response.getJSONObject("arg"));
- }
-
-
- private static final String DATA_KEY = "data";
- private static final String INSTID_KEY = "instId";
- private static final String ORDID_KEY = "ordId";
- private static final String CLORDID_KEY = "clOrdId";
- private static final String SIDE_KEY = "side";
- private static final String TDMODE_KEY = "tdMode";
- private static final String ACCFILLSZ_KEY = "accFillSz";
- private static final String AVGPX_KEY = "avgPx";
- private static final String STATE_KEY = "state";
- private static final String FILLFEE_KEY = "fillFee";
- private static final String POSSIDE_KEY = "posSide";
- public static List<TradeRequestParam> handleEvent(JSONObject response, RedisUtils redisUtils, String accountName) {
-
- log.info("开始执行OrderInfoWs......");
- try {
- JSONArray dataArray = response.getJSONArray(DATA_KEY);
- if (dataArray == null || dataArray.isEmpty()) {
- log.warn("订单频道数据为空");
- return null;
- }
-
- for (int i = 0; i < dataArray.size(); i++) {
- JSONObject detail = dataArray.getJSONObject(i);
-
- String instId = detail.getString(INSTID_KEY);
- if (!CoinEnums.HE_YUE.getCode().equals(instId)){
- log.info( "订单详情-币种: {} 没有成交订单", CoinEnums.HE_YUE.getCode() );
- continue;
- }
- String ordId = detail.getString(ORDID_KEY);
- String clOrdId = detail.getString(CLORDID_KEY);
- String side = detail.getString(SIDE_KEY);
- String tdMode = detail.getString(TDMODE_KEY);
- String accFillSz = detail.getString(ACCFILLSZ_KEY);
- String avgPx = detail.getString(AVGPX_KEY);
- String state = detail.getString(STATE_KEY);
- String fillFee = detail.getString(FILLFEE_KEY);
- String posSide = detail.getString(POSSIDE_KEY);
-
- log.info(
- "{}: 订单详情-币种: {}, 系统编号: {}, 自定义编号: {}, 订单方向: {}, 交易模式: {}," +
- " 累计成交数量: {}, 成交均价: {}, 订单状态: {}, 手续费: {}, 持仓方向: {}",
- accountName, instId, ordId, clOrdId, side, tdMode,
- accFillSz, avgPx,state, fillFee,posSide
- );
-
- String stateStr = TradeOrderWs.getAccountMap(accountName).get("state");
- if (StrUtil.isNotBlank(stateStr) && state.equals(stateStr)){
- // 使用账号特定的Map
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- Map<String, BigDecimal> positionsMap = PositionsWs.getAccountMap(positionAccountName);
- WsMapBuild.saveBigDecimalToMap(positionsMap, CoinEnums.READY_STATE.name(), WsMapBuild.parseBigDecimalSafe(CoinEnums.READY_STATE_NO.getCode()));
-
- Map<String, String> accountWsMap = AccountWs.getAccountMap(accountName);
- WsMapBuild.saveStringToMap(accountWsMap, CoinEnums.READY_STATE.name(), CoinEnums.READY_STATE_NO.getCode());
-
- log.info("{}: 订单详情已完成: {}, 自定义编号: {}", accountName, CoinEnums.HE_YUE.getCode(), clOrdId);
-
- ArrayList<TradeRequestParam> tradeRequestParams = new ArrayList<>();
- TradeRequestParam tradeRequestParam = new TradeRequestParam();
- tradeRequestParam.setAccountName(accountName);
- BigDecimal zhiYingPx = getZhiYingPx(
- accountName,
- posSide,
- fillFee,
- WsMapBuild.parseBigDecimalSafe(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.CTVAL.name())),
- WsMapBuild.parseBigDecimalSafe(accFillSz),
- WsMapBuild.parseBigDecimalSafe(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.CONTRACTMULTIPLIER.name())),
- WsMapBuild.parseBigDecimalSafe(avgPx),
- WsMapBuild.parseBigDecimalSafe(CoinEnums.LEVERAGE.getCode())
- );
- tradeRequestParam.setMarkPx(String.valueOf(zhiYingPx));
- tradeRequestParam.setInstId(CoinEnums.HE_YUE.getCode());
- tradeRequestParam.setTdMode(CoinEnums.CROSS.getCode());
- tradeRequestParam.setPosSide(posSide);
- tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_LIMIT.getCode());
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- tradeRequestParam.setSide(CoinEnums.POSSIDE_LONG.getCode().equals(posSide) ? CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode());
- tradeRequestParam.setClOrdId(WsParamBuild.getOrderNum(tradeRequestParam.getSide()));
- tradeRequestParam.setSz(accFillSz);
- tradeRequestParams.add(tradeRequestParam);
-
- TradeRequestParam tradeRequestParamZhiSun = new TradeRequestParam();
- tradeRequestParamZhiSun.setAccountName(accountName);
- BigDecimal zhiSunPx = getZhiSunPx(
- accountName,
- posSide,
- fillFee,
- WsMapBuild.parseBigDecimalSafe(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.CTVAL.name())),
- WsMapBuild.parseBigDecimalSafe(accFillSz),
- WsMapBuild.parseBigDecimalSafe(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.CONTRACTMULTIPLIER.name())),
- WsMapBuild.parseBigDecimalSafe(avgPx),
- WsMapBuild.parseBigDecimalSafe(CoinEnums.LEVERAGE.getCode())
- );
- tradeRequestParamZhiSun.setMarkPx(String.valueOf(zhiSunPx));
- tradeRequestParamZhiSun.setInstId(CoinEnums.HE_YUE.getCode());
- tradeRequestParamZhiSun.setTdMode(CoinEnums.CROSS.getCode());
- tradeRequestParamZhiSun.setPosSide(posSide);
- tradeRequestParamZhiSun.setOrdType(CoinEnums.ORDTYPE_LIMIT.getCode());
- tradeRequestParamZhiSun.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- tradeRequestParamZhiSun.setSide(CoinEnums.POSSIDE_LONG.getCode().equals(posSide) ? CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode());
- tradeRequestParamZhiSun.setClOrdId(WsParamBuild.getOrderNum(tradeRequestParamZhiSun.getSide()));
- tradeRequestParamZhiSun.setSz(accFillSz);
- tradeRequestParams.add(tradeRequestParamZhiSun);
- return tradeRequestParams;
-
- }
- return null;
- }
- } catch (Exception e) {
- log.error("处理订单频道推送数据失败", e);
- }
- return null;
- }
-
- public static void main(String[] args) {
- System.out.println(
- getZhiYingPx(
- "eth",
- CoinEnums.POSSIDE_LONG.getCode(),
- "0.0001",
- new BigDecimal("0.1"),
- new BigDecimal("0.05"),
- new BigDecimal("1"),
- new BigDecimal("2950"),
- new BigDecimal("100"))
- );
- }
- /**
- * 计算预期收益
- */
- public static BigDecimal getZhiSunPx(
- String accountName, String posSide, String fillFee, BigDecimal coinValue, BigDecimal coinNum,
- BigDecimal contractMultiplier, BigDecimal avgPx, BigDecimal leverage
- ) {
- BigDecimal initMargin = getInitMargin(coinValue, coinNum, contractMultiplier, avgPx, leverage);
- String pingCangImr = StrUtil.isEmpty(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name())) ? "0.2" : InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name());
- BigDecimal expectProfit = (initMargin)
- .multiply(new BigDecimal(pingCangImr))
- .add(new BigDecimal(fillFee).abs())
- .multiply(new BigDecimal("-1"))
- .setScale(4, RoundingMode.DOWN);
- log.info("{}: 订单详情-预期收益: {}", accountName, expectProfit);
- return getMarkPrice(expectProfit,posSide, coinValue, coinNum, contractMultiplier, avgPx, leverage);
- }
- /**
- * 计算预期收益
- */
- public static BigDecimal getZhiYingPx(
- String accountName, String posSide, String fillFee, BigDecimal coinValue, BigDecimal coinNum,
- BigDecimal contractMultiplier, BigDecimal avgPx, BigDecimal leverage
- ) {
- BigDecimal initMargin = getInitMargin(coinValue, coinNum, contractMultiplier, avgPx, leverage);
- String pingCangImr = StrUtil.isEmpty(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name())) ? "0.2" : InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name());
- BigDecimal expectProfit = (initMargin).multiply(new BigDecimal(pingCangImr)).add(new BigDecimal(fillFee).abs()).setScale(4, RoundingMode.DOWN);
- log.info("{}: 订单详情-预期收益: {}", accountName, expectProfit);
- return getMarkPrice(expectProfit,posSide, coinValue, coinNum, contractMultiplier, avgPx, leverage);
- }
-
- /**
- * 计算初始保证金
- * 面值 * 张数 * 合约乘数 * 标记价格 / 杠杆倍数
- */
- public static BigDecimal getInitMargin(BigDecimal coinValue, BigDecimal coinNum, BigDecimal contractMultiplier, BigDecimal avgPx, BigDecimal leverage) {
- BigDecimal initMargin = coinValue.multiply(coinNum).multiply(contractMultiplier).multiply(avgPx).divide(leverage, 4, RoundingMode.DOWN);
- log.info("订单详情-初始保证金: {}", initMargin);
- return initMargin;
- }
- /**
- * USDT保证金合约
- * 多仓收益 = 面值 * |张数| * 合约乘数 *(标记价格 - 开仓均价)
- * (标记价格 - 开仓均价) = 多仓收益 /(面值 * |张数| * 合约乘数)
- * 标记价格 = 多仓收益 /(面值 * |张数| * 合约乘数) + 开仓均价
- * 空仓收益 = 面值 * |张数| * 合约乘数 *(开仓均价 - 标记价格)
- * (开仓均价 - 标记价格) = 空仓收益 /(面值 * |张数| * 合约乘数)
- * 标记价格 = 开仓均价 - 空仓收益 /(面值 * |张数| * 合约乘数)
- */
- public static BigDecimal getMarkPrice(BigDecimal expectProfit,String posSide,BigDecimal coinValue, BigDecimal sz, BigDecimal contractMultiplier, BigDecimal openPrice, BigDecimal leverage) {
- BigDecimal markPrice = BigDecimal.ZERO;
- BigDecimal multiply = coinValue.multiply(sz.abs()).multiply(contractMultiplier);
- BigDecimal bigDecimal = expectProfit.divide(multiply, 2, RoundingMode.DOWN);
- if (CoinEnums.POSSIDE_LONG.getCode().equals(posSide)){
- markPrice = openPrice.add(bigDecimal).setScale(2, RoundingMode.DOWN);
- }
- if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)){
- markPrice = openPrice.subtract(bigDecimal).setScale(2, RoundingMode.DOWN);
- }
- log.info("订单详情-止盈标记价格: {}", markPrice);
- return markPrice;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/PositionsWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/PositionsWs.java
deleted file mode 100644
index 4bb3ca3..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/PositionsWs.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.MallUtils;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * @author Administrator
- */
-@Slf4j
-public class PositionsWs {
-
- // 使用双层Map,第一层key为账号名称,第二层key为数据key
- public static final Map<String, Map<String, BigDecimal>> POSITIONSWSMAP = new ConcurrentHashMap<>();
-
- // 获取指定账号的Map,如果不存在则创建
- public static Map<String, BigDecimal> getAccountMap(String accountName) {
- return POSITIONSWSMAP.computeIfAbsent(accountName, k -> new ConcurrentHashMap<>());
- }
-
- public static final String POSITIONSWS_CHANNEL = "positions";
-
- public static void subscribePositionChannel(WebSocketClient webSocketClient, String option) {
- try {
- JSONArray argsArray = new JSONArray();
- JSONObject args = new JSONObject();
- args.put("channel", POSITIONSWS_CHANNEL);
- args.put("instType", CoinEnums.INSTTYPE_SWAP.getCode());
- args.put("instId", CoinEnums.HE_YUE.getCode());
- argsArray.add(args);
-
- String connId = MallUtils.getOrderNum(POSITIONSWS_CHANNEL);
- JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, option, argsArray);
- webSocketClient.send(jsonObject.toJSONString());
- log.info("发送持仓频道频道:{}", option);
- } catch (Exception e) {
- log.error("订阅持仓频道频道构建失败", e);
- }
- }
-
- public static String initAccountName(String accountName, String posSide) {
- return accountName+"_"+ posSide;
- }
-
- public static void initEvent(JSONObject response, String accountName) {
- log.info("订阅成功,数据初始化: {}", response.getJSONObject("arg"));
- JSONObject arg = response.getJSONObject("arg");
- initParam(arg, accountName,CoinEnums.POSSIDE_LONG.getCode());
- initParam(arg, accountName,CoinEnums.POSSIDE_SHORT.getCode());
- }
-
- public static void handleEvent(JSONObject response, String accountName) {
-
-
-// log.info("开始执行PositionsWs......");
- try {
- JSONArray dataArray = response.getJSONArray("data");
- if (dataArray == null || dataArray.isEmpty()) {
- log.info("账户持仓频道数据为空,等待更新");
- return;
- }
-
- for (int i = 0; i < dataArray.size(); i++) {
- JSONObject posData = dataArray.getJSONObject(i);
- String instId = posData.getString("instId");
- if (CoinEnums.HE_YUE.getCode().equals(instId)) {
-// log.info("查询到账户{}持仓数据",CoinEnums.HE_YUE.getCode());
- String mgnMode = posData.getString("mgnMode");
- String posSide = posData.getString("posSide");
- String pos = posData.getString("pos");
- String avgPx = posData.getString("avgPx");
- String upl = posData.getString("upl");
- String uplRatio = posData.getString("uplRatio");
- String lever = posData.getString("lever");
- String liqPx = posData.getString("liqPx");
- String markPx = posData.getString("markPx");
- String imr = posData.getString("imr");
- String mgnRatio = posData.getString("mgnRatio");
- String mmr = posData.getString("mmr");
- String notionalUsd = posData.getString("notionalUsd");
- String ccy = posData.getString("ccy");
- String last = posData.getString("last");
- String idxPx = posData.getString("idxPx");
- String bePx = posData.getString("bePx");
- String realizedPnl = posData.getString("realizedPnl");
- String settledPnl = posData.getString("settledPnl");
- String fee = posData.getString("fee");
- String fundingFee = posData.getString("fundingFee");
-// log.info(
-// "{}: 账户持仓频道-产品类型: {}, 保证金模式: {}, 持仓方向: {}, 持仓数量: {}, 开仓平均价: {}, "
-// + "未实现收益: {}, 未实现收益率: {}, 杠杆倍数: {}, 预估强平价: {}, 初始保证金: {}, "
-// + "维持保证金率: {}, 维持保证金: {}, 以美金价值为单位的持仓数量: {}, 占用保证金的币种: {}, "
-// + "最新成交价: {}, 最新指数价格: {}, 盈亏平衡价: {}, 已实现收益: {}, 累计已结算收益: {}"
-// + "最新标记价格: {},累计手续费: {},累计持仓费: {},",
-// initAccountName(accountName, posSide), instId, mgnMode, posSide, pos, avgPx,
-// upl, uplRatio, lever, liqPx, imr,
-// mgnRatio, mmr, notionalUsd, ccy,
-// last, idxPx, bePx, realizedPnl, settledPnl,
-// markPx,fee,fundingFee
-// );
- initParam(posData, accountName,posSide);
- }
- }
- } catch (Exception e) {
- log.error("处理持仓频道推送数据失败", e);
- }
- }
-
- private static void initParam(JSONObject posData, String accountName,String posSide) {
- String accountNamePositons = initAccountName(accountName, posSide);
- Map<String, BigDecimal> accountMap = getAccountMap(accountNamePositons);
- WsMapBuild.saveBigDecimalToMap(accountMap, "avgPx", WsMapBuild.parseBigDecimalSafe(posData.getString("avgPx")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "pos", WsMapBuild.parseBigDecimalSafe(posData.getString("pos")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "upl", WsMapBuild.parseBigDecimalSafe(posData.getString("upl")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "imr", WsMapBuild.parseBigDecimalSafe(posData.getString("imr")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "mgnRatio", WsMapBuild.parseBigDecimalSafe(posData.getString("mgnRatio")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "markPx", WsMapBuild.parseBigDecimalSafe(posData.getString("markPx")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "bePx", WsMapBuild.parseBigDecimalSafe(posData.getString("bePx")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "realizedPnl", WsMapBuild.parseBigDecimalSafe(posData.getString("realizedPnl")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "fee", WsMapBuild.parseBigDecimalSafe(posData.getString("fee")));
- WsMapBuild.saveBigDecimalToMap(accountMap, "fundingFee", WsMapBuild.parseBigDecimalSafe(posData.getString("fundingFee")));
-
- BigDecimal ordFrozImr = PositionsWs.getAccountMap(accountNamePositons).get("imr");
- BigDecimal totalOrderUsdt = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get(CoinEnums.TOTAL_ORDER_USDT.name()))
- .divide(new BigDecimal("2"), RoundingMode.DOWN);
- if (ordFrozImr.compareTo(totalOrderUsdt) <= 0){
- WsMapBuild.saveBigDecimalToMap(accountMap, CoinEnums.READY_STATE.name(), WsMapBuild.parseBigDecimalSafe(CoinEnums.READY_STATE_YES.getCode()));
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java
deleted file mode 100644
index bea34fd..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java
+++ /dev/null
@@ -1,247 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONUtil;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
-import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 交易订单处理类,负责构建和发送订单请求到OKX WebSocket
- *
- * @author Administrator
- */
-@Slf4j
-public class TradeOrderWs {
-
- // 使用双层Map,第一层key为账号名称,第二层key为数据key
- public static final Map<String, Map<String,String>> TRADEORDERWSMAP = new ConcurrentHashMap<>();
-
- // 获取指定账号的Map,如果不存在则创建
- public static Map<String, String> getAccountMap(String accountName) {
- return TRADEORDERWSMAP.computeIfAbsent(accountName, k -> new ConcurrentHashMap<>());
- }
-
- public static final String ORDERWS_CHANNEL = "order";
- public static final String BATCH_ORDERSWS_CHANNEL = "batch-orders";
-
- public static void orderEvent(WebSocketClient webSocketClient, TradeRequestParam tradeRequestParam) {
-
-
- log.info("开始执行TradeOrderWs{}......", JSONUtil.parse(tradeRequestParam));
- String accountName = tradeRequestParam.getAccountName();
- String markPx = tradeRequestParam.getMarkPx();
- String instId = tradeRequestParam.getInstId();
- String tdMode = tradeRequestParam.getTdMode();
- String posSide = tradeRequestParam.getPosSide();
- String ordType = tradeRequestParam.getOrdType();
-
- String tradeType = tradeRequestParam.getTradeType();
-
- String clOrdId = tradeRequestParam.getClOrdId();
- String side = tradeRequestParam.getSide();
- String sz = tradeRequestParam.getSz();
- log.info("账户:{},类型:{},触发价格:{},币种:{},方向:{},买卖:{},数量:{},是否允许下单:{},编号:{},",
- accountName,ordType, markPx, instId, posSide,side, sz, tradeType, clOrdId);
- //验证是否允许下单
- if (StrUtil.isNotEmpty(tradeType) && OrderParamEnums.TRADE_NO.getValue().equals(tradeType)) {
- log.warn("账户{}不允许下单,取消发送", accountName);
- return;
- }
- /**
- * 校验必要参数
- * 验证下单参数是否存在空值
- */
- if (
- StrUtil.isBlank(accountName)
- || StrUtil.isBlank(instId)
- || StrUtil.isBlank(tdMode)
- || StrUtil.isBlank(posSide)
- || StrUtil.isBlank(ordType)
- || StrUtil.isBlank(clOrdId)
- || StrUtil.isBlank(side)
- || StrUtil.isBlank(sz)
-
- ){
- log.warn("下单参数缺失,取消发送");
- return;
- }
- if (BigDecimal.ZERO.compareTo(new BigDecimal(sz)) >= 0) {
- log.warn("下单数量{}不允许下单,取消发送", sz);
- return;
- }
-
- /**
- * 检验账户和仓位是否准备就绪
- * 开多:买入开多(side 填写 buy; posSide 填写 long )
- * 开空:卖出开空(side 填写 sell; posSide 填写 short ) 需要检验账户通道是否准备就绪
- * 平多:卖出平多(side 填写 sell;posSide 填写 long )
- * 平空:买入平空(side 填写 buy; posSide 填写 short ) 需要检验仓位通道是否准备就绪
- */
- //买入开多、卖出开空则验证仓位通道是否准备就绪
-
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- boolean b = posSide.equals(CoinEnums.POSSIDE_LONG.getCode()) && side.equals(CoinEnums.SIDE_BUY.getCode());
- boolean c = posSide.equals(CoinEnums.POSSIDE_SHORT.getCode()) && side.equals(CoinEnums.SIDE_SELL.getCode());
- if ( b || c ){
- BigDecimal positionsReadyState = PositionsWs.getAccountMap(positionAccountName).get(CoinEnums.READY_STATE.name()) == null
- ? BigDecimal.ZERO : PositionsWs.getAccountMap(positionAccountName).get(CoinEnums.READY_STATE.name());
- if (WsMapBuild.parseBigDecimalSafe(CoinEnums.READY_STATE_YES.getCode()).compareTo(positionsReadyState) != 0) {
- log.info("仓位{}通道未就绪,取消发送",positionAccountName);
- return;
- }
- String accountReadyState = AccountWs.getAccountMap(accountName).get(CoinEnums.READY_STATE.name());
- if (!CoinEnums.READY_STATE_YES.getCode().equals(accountReadyState)) {
- log.info("账户通道未就绪,取消发送");
- return;
- }
- }
-
- try {
- JSONArray argsArray = new JSONArray();
- JSONObject args = new JSONObject();
- args.put("instId", instId);
- args.put("tdMode", tdMode);
- args.put("clOrdId", clOrdId);
- args.put("side", side);
-
- args.put("posSide", posSide);
- args.put("ordType", ordType);
- args.put("sz", sz);
- argsArray.add(args);
-
- String connId = WsParamBuild.getOrderNum(ORDERWS_CHANNEL);
- JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, ORDERWS_CHANNEL, argsArray);
- webSocketClient.send(jsonObject.toJSONString());
- log.info("发送下单频道:{},数量:{}", side, sz);
-
- WsMapBuild.saveStringToMap(getAccountMap(accountName), "state", CoinEnums.ORDER_FILLED.getCode());
- /**
- * 将状态更新为未准备就绪
- */
- WsMapBuild.saveBigDecimalToMap(PositionsWs.getAccountMap(positionAccountName), CoinEnums.READY_STATE.name(), WsMapBuild.parseBigDecimalSafe(CoinEnums.READY_STATE_NO.getCode()));
- WsMapBuild.saveStringToMap(AccountWs.getAccountMap(accountName), CoinEnums.READY_STATE.name(), CoinEnums.READY_STATE_NO.getCode());
-
- } catch (Exception e) {
- log.error("下单构建失败", e);
- }
- }
-
- public static void orderZhiYingZhiSunEventNoState(WebSocketClient webSocketClient, List<TradeRequestParam> tradeRequestParams) {
-
-
- log.info("开始执行TradeOrderWs......");
- if (tradeRequestParams == null){
-
- log.warn("下单{}参数缺失,取消发送",tradeRequestParams);
- return;
- }
-
- JSONArray argsArray = new JSONArray();
- for (TradeRequestParam tradeRequestParam : tradeRequestParams){
- String accountName = tradeRequestParam.getAccountName();
- String markPx = tradeRequestParam.getMarkPx();
- String instId = tradeRequestParam.getInstId();
- String tdMode = tradeRequestParam.getTdMode();
- String posSide = tradeRequestParam.getPosSide();
- String ordType = tradeRequestParam.getOrdType();
-
- String tradeType = tradeRequestParam.getTradeType();
-
- String clOrdId = tradeRequestParam.getClOrdId();
- String side = tradeRequestParam.getSide();
- String sz = tradeRequestParam.getSz();
- /**
- * 校验必要参数
- * 验证下单参数是否存在空值
- */
- if (
- StrUtil.isBlank(accountName)
- || StrUtil.isBlank(instId)
- || StrUtil.isBlank(tdMode)
- || StrUtil.isBlank(posSide)
- || StrUtil.isBlank(ordType)
- || StrUtil.isBlank(clOrdId)
- || StrUtil.isBlank(side)
- || StrUtil.isBlank(sz)
- || StrUtil.isBlank(markPx)
-
- ){
- log.warn("下单参数缺失,取消发送");
- continue;
- }
- log.info("账户:{},类型:{},触发价格:{},币种:{},方向:{},买卖:{},数量:{},是否允许下单:{},编号:{},",
- accountName,ordType, markPx, instId, posSide,side, sz, tradeType, clOrdId);
- //验证是否允许下单
- if (StrUtil.isNotEmpty(tradeType) && OrderParamEnums.TRADE_NO.getValue().equals(tradeType)) {
- log.warn("账户{}不允许下单,取消发送", accountName);
- continue;
- }
-
- /**
- * 检验账户和仓位是否准备就绪
- * 开多:买入开多(side 填写 buy; posSide 填写 long )
- * 开空:卖出开空(side 填写 sell; posSide 填写 short ) 需要检验账户通道是否准备就绪
- * 平多:卖出平多(side 填写 sell;posSide 填写 long )
- * 平空:买入平空(side 填写 buy; posSide 填写 short ) 需要检验仓位通道是否准备就绪
- */
-
- JSONObject args = new JSONObject();
- args.put("instId", instId);
- args.put("tdMode", tdMode);
- args.put("clOrdId", clOrdId);
- args.put("side", side);
-
- args.put("posSide", posSide);
- args.put("ordType", ordType);
- args.put("sz", sz);
- args.put("px", markPx);
- argsArray.add(args);
- }
-
- String connId = WsParamBuild.getOrderNum(null);
- JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, BATCH_ORDERSWS_CHANNEL, argsArray);
- webSocketClient.send(jsonObject.toJSONString());
- log.info("发送止盈止损批量下单频道:{}",argsArray);
- }
-
-
-
- /**
- * 计算盈亏金额。
- *
- * @param faceValue 面值
- * @param position 持仓数量
- * @param markPrice 标记价格
- * @param openPrice 开仓价格
- * @param isLong 是否为多头仓位
- * @param minTickSz 最小变动单位精度
- * @return 盈亏金额,保留指定精度的小数位
- */
- public BigDecimal profit(BigDecimal faceValue, BigDecimal position,
- BigDecimal markPrice, BigDecimal openPrice, boolean isLong, int minTickSz) {
- BigDecimal profit = BigDecimal.ZERO;
- if (isLong) {
- profit = markPrice.subtract(openPrice)
- .multiply(faceValue)
- .multiply(position);
- } else {
- profit = openPrice.subtract(markPrice)
- .multiply(faceValue)
- .multiply(position);
- }
- return profit.setScale(minTickSz, BigDecimal.ROUND_DOWN);
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/CoinEnums.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/CoinEnums.java
deleted file mode 100644
index 8429c7d..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/CoinEnums.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.enums;
-
-import lombok.Getter;
-
-/**
- * @author Administrator
- */
-@Getter
-public enum CoinEnums {
-
- /**
- * 0: 仅根据持仓事件推送数据
- * 2000, 3000, 4000: 根据持仓事件推送,且根据设置的时间间隔定时推送(ms)
- *
- * 若不添加该字段或将其设置为上述合法值以外的其他值,数据将根据事件推送并大约每 5 秒定期推送一次
- */
- UPDATEINTERVAL("2000","2000"),
-
- ORDER_FILLED("filled","filled"),
- ORDER_LIVE("live","live"),
-
- INSTTYPE_SWAP("SWAP","SWAP"),
-
- ORDTYPE_MARKET("market","market"),
- ORDTYPE_LIMIT("limit","limit"),
-
- POSSIDE_SHORT("short","short"),
-
- POSSIDE_LONG("long","long"),
-
- SIDE_SELL("sell","sell"),
-
- SIDE_BUY("buy","buy"),
-
- CROSS("cross","cross"),
-
- USDT("USDT","USDT"),
-
-
- WANG_GE_OLD("上一个网格wang_ge_old", "0"),
-
- READY_STATE("是否准备就绪ready_state", "1"),
- READY_STATE_YES("准备就绪ready_state", "1"),
- READY_STATE_NO("未准备就绪ready_state", "0"),
-
- PING_CANG_SHOUYI("平仓收益比例", "1"),
- //下单的总保障金为账户总金额cashBal * TOTAL_ORDER_USDT用来做保证金
- TOTAL_ORDER_USDTPECENT("总保证金比例total_order_usdtpecent","0.06"),
- TOTAL_ORDER_USDT("总保证金totalOrderUsdt","0"),
- KANG_CANG("抗压比例KANG_CANG","0.9"),
- ZHI_SUN("止损比例ZHI_SUN","0.8"),
- //每次下单的张数
- BUY_CNT("每次开仓的张数buyCnt","0.5"),
- BUY_CNT_INIT("每次初始化开仓张数的基础值buyCntInit","0.5"),
- BUY_CNT_TIME("每次开仓张数的倍数基础值buyCntTime","20"),
- OUT("是否允许下单out","操作中"),
- CTVAL("合约面值ctVal","0.1"),
- CONTRACTMULTIPLIER("合约乘积ctVal","1"),
- TICKSZ("下单价格精度tickSz","2"),
- MINSZ("最小下单数小数位minSz","2"),
- LEVERAGE("合约杠杆leverage","100"),
-// HE_YUE("合约instId","ETH-USDT-SWAP"),
- HE_YUE("合约instId","BTC-USDT-SWAP"),
- POSSIDE("持仓方向posSide","short");
-
- private String name;
-
- private String code;
-
- /**
- * 构造方法
- *
- * @param name
- * @param code
- */
- CoinEnums(String name, String code) {
- this.name = name;
- this.code = code;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/ExchangeInfoEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/ExchangeInfoEnum.java
deleted file mode 100644
index 42a1d83..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/ExchangeInfoEnum.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.enums;
-
-import lombok.Getter;
-
-/**
- * 交易信息枚举类
- * 用于存储不同交易账户的密钥信息,包括实盘账户和模拟账户
- */
-@Getter
-public enum ExchangeInfoEnum {
-
- /**
- * 模拟盘账户1信息
- * 存储了模拟盘交易所需的API密钥、秘钥和通过码
- */
-// OKX_PRD_xiao("f512673b-2685-4fcb-9bb1-2ae8db745d62",
-// "B0C1CC8F39625B41140D93DC25039E33",
-// "Aa12345678@",
-// true);
- OKX_UAT_ceshi("ffb4e79f-fcf5-4afb-82c5-2fbb64123f61",
- "AA06C5ED1D7C7F5AFE6484052E231C55",
- "Aa12345678@",
- false);
-//
-// /**
-// * 模拟盘账户2信息
-// * 存储了模拟盘交易所需的API密钥、秘钥和通过码
-// */
-// OKX_PRD_wang("72e380a6-4133-451b-8b10-8b1905b30717",
-// "2A5BD55BF0771F1ADF08AE0A2FB4D561",
-// "Aa12345678@",
-// true);
-// OKX_UAT2("7a023eb2-06c0-4255-9969-b86ea1cef0d7",
-// "D0106A4D63BD22BEAB9CBA8F41219661",
-// "Aa12345678@",
-// false);
-
- /**
- * 模拟盘账户3信息
- * 存储了模拟盘交易所需的API密钥、秘钥和通过码
- */
-// OKX_UAT3("0769b50c-2c36-4310-8bd9-cad6bc6c9d8f",
-// "7AF4A574BC44907CE76BBFF91F53852D",
-// "Aa123456@",
-// false);
-
- // API公钥,用于识别用户身份
- private String apiKey;
-
- // API秘钥,用于签名和验证请求
- private String secretKey;
-
- // API通过码,用于额外的身份验证
- private String passphrase;
-
- // 账户类型,true表示实盘账户,false表示模拟账户
- private boolean accountType;
-
- /**
- * 构造方法
- *
- * @param apiKey API公钥,用于识别用户身份
- * @param secretKey API秘钥,用于签名和验证请求
- * @param passphrase API通过码,用于额外的身份验证
- * @param accountType 账户类型,true表示实盘账户,false表示模拟账户
- */
- ExchangeInfoEnum(String apiKey, String secretKey, String passphrase, boolean accountType) {
- this.apiKey = apiKey;
- this.secretKey = secretKey;
- this.passphrase = passphrase;
- this.accountType = accountType;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/OrderParamEnums.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/OrderParamEnums.java
deleted file mode 100644
index 981203e..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/enums/OrderParamEnums.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.enums;
-
-import com.xcong.excoin.common.enumerates.SymbolEnum;
-import lombok.Getter;
-
-/**
- * @author Administrator
- */
-
-@Getter
-public enum OrderParamEnums {
-
- TRADE_YES("允许下单", "TRADE_YES"),
- TRADE_NO("拒绝下单", "TRADE_NO"),
-
- OUT_NO("操作中", "操作中"),
- OUT_YES("冷静中", "冷静中"),
-
- ORDERING("操作下单中", "ORDERING"),
- LIMIT("限价止损", "limit"),
- OUT("止损", "out"),
- INIT("初始化", "init"),
- HOLDING("持仓", "holding"),
- BUY("买", "buy"),
- SELL("卖", "sell")
- ;
-
- private String name;
-
- private String value;
-
- private OrderParamEnums(String name, String value) {
- this.name = name;
- this.value = value;
- }
-
- public static String getNameByValue(String value) {
- String name = "";
- for (OrderParamEnums orderParamEnum : values()) {
- if (value.equals(orderParamEnum.getValue())){
- name = orderParamEnum.getName();
- break;
- }
- }
- return name;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/Kline.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/Kline.java
deleted file mode 100644
index 5adafea..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/Kline.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.param;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-@Data
-public class Kline{
- private String ts;
- private BigDecimal o;
- private BigDecimal h;
- private BigDecimal l;
- private BigDecimal c;
- private BigDecimal vol;
- private String confirm;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/StrategyParam.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/StrategyParam.java
deleted file mode 100644
index 5dcd018..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/StrategyParam.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.param;
-
-import lombok.Data;
-
-/**
- * @author Administrator
- */
-@Data
-public class StrategyParam {
- private String accountName;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/TradeRequestParam.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/TradeRequestParam.java
deleted file mode 100644
index 14260d7..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/param/TradeRequestParam.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.param;
-
-import lombok.Data;
-
-/**
- * @author Administrator
- */
-@Data
-public class TradeRequestParam {
- /**
- * 这些参数由 caoZuoHandler方法提供
- */
- private String accountName;
- private String markPx;
-
- private String instId;
- private String tdMode;
- private String posSide;
- private String ordType;
-
- /**
- * 决定是否进行下单操作
- */
- private String tradeType;
- /**
- * 这些参数由 caoZuoLong 或者 caoZuoShort 提供
- */
- private String side;
- private String clOrdId;
- private String sz;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListEnum.java
deleted file mode 100644
index 7ad9442..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListEnum.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList;
-
-import lombok.Getter;
-
-import java.math.BigDecimal;
-
-/**
- * @author Administrator
- * 网格数据枚举 数据
- * todo 后期考虑优化为可配置项
- */
-@Getter
-public enum WangGeListEnum {
- UP("上层做空", "2", "3200", "3000", "4", "short", "3100"),
- CENTER("中间做空", "2", "3000", "2700", "4", "short", "2700"),
- DOWN("下层做多", "2", "2700", "2500", "4", "long", "2500"),
- DOWN_ONE("下层做空", "2", "2500", "2200", "4", "short", "2500");
-
- private String name;
- private String xiaoshu_weishu;
- private String jiage_shangxian;
- private String jiage_xiaxian;
- private String jian_ju;
- private String fang_xiang;
- private String zhi_sun_dian;
-
- WangGeListEnum(String name, String xiaoshu_weishu, String jiage_shangxian, String jiage_xiaxian, String jian_ju, String fang_xiang, String zhi_sun_dian) {
- this.name = name;
- this.xiaoshu_weishu = xiaoshu_weishu;
- this.jiage_shangxian = jiage_shangxian;
- this.jiage_xiaxian = jiage_xiaxian;
- this.jian_ju = jian_ju;
- this.fang_xiang = fang_xiang;
- this.zhi_sun_dian = zhi_sun_dian;
- }
-
- /**
- * 根据价格获取匹配的网格信息
- * @param price 待比较的价格
- * @return 匹配的网格枚举信息,如果没有匹配项则返回null
- */
- public static WangGeListEnum getGridByPrice(BigDecimal price) {
- for (WangGeListEnum grid : WangGeListEnum.values()) {
- BigDecimal upperLimit = new BigDecimal(grid.jiage_shangxian);
- BigDecimal lowerLimit = new BigDecimal(grid.jiage_xiaxian);
-
- // 确保上限大于下限
- if (upperLimit.compareTo(lowerLimit) > 0) {
- // 检查价格是否在区间内
- if (price.compareTo(lowerLimit) > 0 && price.compareTo(upperLimit) <= 0) {
- return grid;
- }
- }
- }
- return null;
- }
-
- /**
- * 根据枚举名称获取枚举
- */
- public static WangGeListEnum getByName(String name) {
- for (WangGeListEnum grid : WangGeListEnum.values()) {
- if (grid.name.equals(name)) {
- return grid;
- }
- }
- return null;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListQueue.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListQueue.java
deleted file mode 100644
index 70ae5a0..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListQueue.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList;
-
-import com.xcong.excoin.rabbit.pricequeue.AscBigDecimal;
-import com.xcong.excoin.rabbit.pricequeue.DescBigDecimal;
-
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 网格交易队列管理类
- *
- * 用于管理系统中各种网格交易相关的优先级阻塞队列,
- * 包括完整的网格队列、平仓队列和开仓队列。
- *
- * @author Administrator
- */
-public class WangGeListQueue {
-
- //------------------------------------------------------------------------------------------------------------------
- //------------------------------------------------------------------------------------------------------------------
- // todo 系统启动后,初始化网格队列
- /**
- * 完整的网格 头元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> QUEUE_ASC = null;
-
-
- //------------------------------------------------------------------------------------------------------------------
- //------------------------------------------------------------------------------------------------------------------
- // todo 当用户下了第一单后,根据开仓价格初始化网格平仓队列和开仓队列
- /**
- * 网格平仓队列 头元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> QUEUE_PINGCANG_ASC = null;
-
- /**
- * 网格开仓队列 头元素最大
- */
- public static PriorityBlockingQueue<DescBigDecimal> QUEUE_KAICANG_DESC = null;
-
- /**
- * 获取完整的网格队列(升序)
- * 如果队列未初始化则创建新的优先级阻塞队列
- *
- * @return 返回升序排列的PriorityBlockingQueue队列,队列头部元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> getQueueAsc() {
- if (QUEUE_ASC == null) {
- QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return QUEUE_ASC;
- }
-
- /**
- * 获取网格平仓队列(升序)
- * 如果队列未初始化则创建新的优先级阻塞队列
- *
- * @return 返回升序排列的PriorityBlockingQueue队列,队列头部元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> getPingCang() {
- if (QUEUE_PINGCANG_ASC == null) {
- QUEUE_PINGCANG_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return QUEUE_PINGCANG_ASC;
- }
-
- /**
- * 获取网格开仓队列(降序)
- * 如果队列未初始化则创建新的优先级阻塞队列
- *
- * @return 返回降序排列的PriorityBlockingQueue队列,队列头部元素最大
- */
- public static PriorityBlockingQueue<DescBigDecimal> getKaiCang() {
- if (QUEUE_KAICANG_DESC == null) {
- QUEUE_KAICANG_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return QUEUE_KAICANG_DESC;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListService.java
deleted file mode 100644
index b8b304a..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList;
-
-import com.xcong.excoin.rabbit.pricequeue.AscBigDecimal;
-import com.xcong.excoin.rabbit.pricequeue.DescBigDecimal;
-
-import java.math.BigDecimal;
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 网格交易服务接口
- * 定义了网格交易的核心操作方法,包括初始化网格、开仓和平仓等操作
- * @author Administrator
- */
-public interface WangGeListService {
-
- /**
- * 初始化网格交易
- * 创建并初始化用于网格交易的价格队列,按照价格升序排列
- * @return 初始化结果信息,返回按价格升序排列的阻塞队列
- */
- PriorityBlockingQueue<AscBigDecimal> initWangGe(String markPx);
-
- /**
- * 初始化开仓操作
- * 根据指定价格初始化开仓队列,将开仓价格点加入到价格队列中
- * @param jiaGe 开仓价格
- * @param queueAsc 价格队列,用于存储按升序排列的价格点
- */
- PriorityBlockingQueue<DescBigDecimal> initKaiCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc);
-
- /**
- * 初始化平仓操作
- * 根据指定价格初始化平仓队列,将平仓价格点加入到价格队列中
- * @param jiaGe 开仓价格
- * @param queueAsc 价格队列,用于存储按升序排列的价格点
- */
- PriorityBlockingQueue<AscBigDecimal> initPingCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc);
-
-
-}
-
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListServiceImpl.java
deleted file mode 100644
index 6b3b1d6..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/wanggeList/WangGeListServiceImpl.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList;
-
-import com.xcong.excoin.rabbit.pricequeue.AscBigDecimal;
-import com.xcong.excoin.rabbit.pricequeue.DescBigDecimal;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 网格交易服务实现类,用于初始化价格网格、开仓和平仓操作。
- *
- * @author Administrator
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class WangGeListServiceImpl implements WangGeListService {
-
- /**
- * 初始化价格网格队列。根据配置的价格上限、下限和间隔生成一系列价格点,
- * 并将这些价格点存入升序优先阻塞队列中。
- *
- * @return 返回初始化完成的升序价格队列;若初始化失败则返回null
- */
- @Override
- public PriorityBlockingQueue<AscBigDecimal> initWangGe(String markPx) {
- log.info("网格初始化中");
- PriorityBlockingQueue<AscBigDecimal> queueAsc = WangGeListQueue.getQueueAsc();
- queueAsc.clear();
-
- //获取WangGeListEnum全部网格参数
- WangGeListEnum gridByPrice = WangGeListEnum.getGridByPrice(new BigDecimal(markPx));
- log.info("获取的网格参数: {}", gridByPrice);
- if (gridByPrice == null){
- log.error("没有获取到网格参数......");
- return null;
- }
-
- String shangxianValue = gridByPrice.getJiage_shangxian();
- String xiaxianValue = gridByPrice.getJiage_xiaxian();
- String jianjuValue = gridByPrice.getJian_ju();
- String weishuValueStr = gridByPrice.getXiaoshu_weishu();
-
- try {
- BigDecimal shangxian = new BigDecimal(shangxianValue);
- BigDecimal xiaxian = new BigDecimal(xiaxianValue);
- BigDecimal jianju = new BigDecimal(jianjuValue);
-
- if (jianju.compareTo(BigDecimal.ZERO) == 0) {
- log.error("价格间隔不能为0");
- return null;
- }
-
- int weishu = Integer.parseInt(weishuValueStr);
- BigDecimal diff = shangxian.subtract(xiaxian);
- int count = diff.divide(jianju, 0, RoundingMode.DOWN).intValue();
-
- BigDecimal currentStep = BigDecimal.ZERO;
- for (int i = 0; i <= count; i++) {
- BigDecimal stepMultiplier = currentStep.multiply(jianju);
- BigDecimal wangGeJiaGe = xiaxian.add(stepMultiplier).setScale(weishu, RoundingMode.DOWN);
- AscBigDecimal ascBigDecimal = new AscBigDecimal(wangGeJiaGe.toString());
- queueAsc.add(ascBigDecimal);
- currentStep = currentStep.add(BigDecimal.ONE);
- }
-
- if (queueAsc.isEmpty()) {
- log.info("网格初始化失败");
- return null;
- }
-
- return queueAsc;
- } catch (NumberFormatException e) {
- log.error("解析价格参数失败", e);
- return null;
- } catch (Exception e) {
- log.error("初始化网格发生未知异常", e);
- return null;
- }
- }
-
- /**
- * 根据当前价格初始化开仓队列。遍历已有的升序价格队列,
- * 将小于当前价格的所有价格点加入降序的开仓队列中。
- *
- * @param jiaGe 当前价格
- * @param queueAsc 已初始化的价格升序队列
- */
- @Override
- public PriorityBlockingQueue<DescBigDecimal> initKaiCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc) {
- PriorityBlockingQueue<DescBigDecimal> queueKaiCang = WangGeListQueue.getKaiCang();
- queueKaiCang.clear();
-
- AscBigDecimal now = new AscBigDecimal(jiaGe.toString());
-
- for (AscBigDecimal ascBigDecimal : queueAsc) {
- if (ascBigDecimal.compareTo(now) < 0) {
- DescBigDecimal kaiCangJia = new DescBigDecimal(ascBigDecimal.getValue().toString());
- queueKaiCang.add(kaiCangJia);
- }
- }
- StringBuilder kaiCangStr = new StringBuilder();
- kaiCangStr.append("初始化下限队列: [");
- boolean first = true;
- for (DescBigDecimal item : queueKaiCang) {
- if (!first) {
- kaiCangStr.append(", ");
- }
- kaiCangStr.append(item.getValue());
- first = false;
- }
- kaiCangStr.append("]");
- log.info(kaiCangStr.toString());
-
- return queueKaiCang;
- }
-
- /**
- * 根据当前价格初始化平仓队列。遍历已有的升序价格队列,
- * 将大于当前价格的所有价格点加入升序的平仓队列中。
- *
- * @param jiaGe 当前价格
- * @param queueAsc 已初始化的价格升序队列
- */
- @Override
- public PriorityBlockingQueue<AscBigDecimal> initPingCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc) {
- PriorityBlockingQueue<AscBigDecimal> queuePingCang = WangGeListQueue.getPingCang();
- queuePingCang.clear();
-
- AscBigDecimal now = new AscBigDecimal(jiaGe.toString());
-
- for (AscBigDecimal ascBigDecimal : queueAsc) {
- if (ascBigDecimal.compareTo(now) > 0) {
- queuePingCang.add(ascBigDecimal);
- }
- }
-
- StringBuilder pingCangStr = new StringBuilder();
- pingCangStr.append("初始化上限队列: [");
- boolean first = true;
- for (AscBigDecimal item : queuePingCang) {
- if (!first) {
- pingCangStr.append(", ");
- }
- pingCangStr.append(item.getValue());
- first = false;
- }
- pingCangStr.append("]");
- log.info(pingCangStr.toString());
-
- return queuePingCang;
- }
-
- /**
- * 主方法,用于测试网格初始化及开仓/平仓逻辑。
- * 示例使用固定价格"0.355"进行模拟调用。
- *
- * @param args 启动参数(未使用)
- */
- public static void main(String[] args) {
- WangGeListServiceImpl wangGeService = new WangGeListServiceImpl();
- String openPx = "2875";
- String markPx = "2905";
- String orderPx = "2895";
- PriorityBlockingQueue<AscBigDecimal> queueAsc = wangGeService.initWangGe(openPx);
- if (queueAsc != null) {
- wangGeService.initKaiCang(new BigDecimal(orderPx), queueAsc);
- wangGeService.initPingCang(new BigDecimal(orderPx), queueAsc);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/DataUtil.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/DataUtil.java
deleted file mode 100644
index 4992a3b..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/DataUtil.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi;
-
-import java.math.BigDecimal;
-
-/**
- * 时间工具类
- *
- * @author MrBird
- */
-public class DataUtil {
-
- //输入两个整数a、b,a/b取模,输出模,如果有余数,输出模+1
- public static int mod(int a, int b) {
- int mod = a / b;
- if (mod != 0) {
- return mod + 1;
- }
- return mod;
- }
-
- public static void main(String[] args) {
- System.out.println(getDecimalDigits8("3422.66666666666666"));
- }
-
- //输入一个字符串类的小数,输出小数位数
- public static int getDecimalDigits(String num) {
- if( num.indexOf(".") == -1){
- return Integer.valueOf(num);
- } else {
- return String.valueOf(num).split("\\.")[1].length(); //split() 方法用于把一个字符串分割成字符串数组。
- }
- }
-
- //输入一个BigDecimal类的小数,输出小数位数,
- public static int getDecimalDigitsNew(BigDecimal num) {
- //除去小数点后多余的0
- num = num.stripTrailingZeros();
- if (num.scale() == 0) {
- return 0;
- } else {
- return num.scale(); //scale() 方法返回小数点后的位数。
- }
- }
-
- //输入一个包含有小数的字符串,输出原字符串,如果小数位数超过8位,则保留8位小数
- public static String getDecimalDigits8(String num) {
- if (getDecimalDigits(num) > 8) {
- return String.format("%.8f", Double.valueOf(num));
- } else {
- return num;
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/MallUtils.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/MallUtils.java
deleted file mode 100644
index 9f378bf..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/MallUtils.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi;
-
-import cn.hutool.core.util.StrUtil;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Random;
-
-/**
- * @author wzy
- * @date 2021-09-22
- **/
-public class MallUtils {
-
- public static String getRandomNum(int length) {
- String str = "0123456789";
- Random random = new Random();
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; ++i) {
- int number = random.nextInt(str.length());
- sb.append(str.charAt(number));
- }
-
- return sb.toString();
- }
-
- public static String getOrderNum(String prefix) {
- SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
- String dd=df.format(new Date());
- if (StrUtil.isNotBlank(prefix)) {
- return prefix+dd+getRandomNum(5);
- }
- return dd+getRandomNum(5);
- }
-
- public static String getOrderNum() {
- return getOrderNum(null);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/QuantApiMessage.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/QuantApiMessage.java
deleted file mode 100644
index 48be097..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/QuantApiMessage.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto;
-
-import lombok.Data;
-
-/**
- * 交易所信息绑定
- */
-@Data
-public class QuantApiMessage{
- private Long memberId;//用户ID
- private String exchange;//交易所名称
- private String aSecretkey;//A秘钥(access_key)
- private String bSecretkey;//s秘钥(secret_key)
- private String passPhrass;//passphrass
- private String accountType;//账户类型 true:正式 false:测试
- private int state;//是否成功连通账户 0-失败 1-成功
- private int isTrade;//是否可交易 1.是 2-否
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/SubmitOrderReqDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/SubmitOrderReqDto.java
deleted file mode 100644
index 9a1cd32..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/SubmitOrderReqDto.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto;
-
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class SubmitOrderReqDto {
- /**
- * 是 当前价
- */
- private String price;
- /**
- * 是 产品ID,如 BTC-USDT
- */
- private String instId;
- /**
- * 是 交易模式
- * 保证金模式:isolated:逐仓 ;cross:全仓
- * 非保证金模式:cash:非保证金
- * spot_isolated:现货逐仓(仅适用于现货带单) ,现货带单时,tdMode 的值需要指定为spot_isolated
- */
- private String tdMode;
- /**
- * 否 保证金币种,仅适用于现货和合约模式下的全仓杠杆订单
- */
- private String ccy;
- /**
- * 否 客户自定义订单ID
- * 字母(区分大小写)与数字的组合,可以是纯字母、纯数字且长度要在1-32位之间。
- */
- private String clOrdId;
- /**
- * 否 订单标签
- * 字母(区分大小写)与数字的组合,可以是纯字母、纯数字,且长度在1-16位之间。
- */
- private String tag;
- /**
- * 是 订单方向
- * buy:买, sell:卖
- */
- private String side;
- /**
- * 可选 持仓方向
- * 在开平仓模式下必填,且仅可选择 long 或 short。 仅适用交割、永续。
- */
- private String posSide;
- /**
- * 是 订单类型
- * market:市价单
- * limit:限价单
- * post_only:只做maker单
- * fok:全部成交或立即取消
- * ioc:立即成交并取消剩余
- * optimal_limit_ioc:市价委托立即成交并取消剩余(仅适用交割、永续)
- * mmp:做市商保护(仅适用于组合保证金账户模式下的期权订单)
- * mmp_and_post_only:做市商保护且只做maker单(仅适用于组合保证金账户模式下的期权订单)
- */
- private String ordType;
- /**
- * 是 委托数量
- */
- private String sz;
- /**
- * 可选 委托价格,仅适用于limit、post_only、fok、ioc、mmp、mmp_and_post_only类型的订单
- * 期权下单时,px/pxUsd/pxVol 只能填一个
- */
- private String px;
- /**
- * 可选 以USD价格进行期权下单
- * 仅适用于期权
- * 期权下单时 px/pxUsd/pxVol 必填一个,且只能填一个
- */
- private String pxUsd;
- /**
- * 可选 以隐含波动率进行期权下单,例如 1 代表 100%
- * 仅适用于期权
- * 期权下单时 px/pxUsd/pxVol 必填一个,且只能填一个
- */
- private String pxVol;
- /**
- * 否 是否只减仓,true 或 false,默认false
- * 仅适用于币币杠杆,以及买卖模式下的交割/永续
- * 仅适用于现货和合约模式和跨币种保证金模式
- */
- private Boolean reduceOnly;
- /**
- * 否 市价单委托数量sz的单位,仅适用于币币市价订单
- * base_ccy: 交易货币 ;quote_ccy:计价货币
- * 买单默认quote_ccy, 卖单默认base_ccy
- */
- private String tgtCcy;
- /**
- * 否 是否禁止币币市价改单,true 或 false,默认false
- * 为true时,余额不足时,系统不会改单,下单会失败,仅适用于币币市价单
- */
- private Boolean banAmend;
- /**
- * 否 自成交保护模式
- * 默认为 cancel maker
- * cancel_maker,cancel_taker, cancel_both
- * Cancel both不支持FOK
- */
- private String stpMode;
- /**
- * 否 下单附带止盈止损信息
- */
- private List<Object> attachAlgoOrds;
- /**
- * 否 下单附带止盈止损时,客户自定义的策略订单ID
- * 字母(区分大小写)与数字的组合,可以是纯字母、纯数字且长度要在1-32位之间。
- * 订单完全成交,下止盈止损委托单时,该值会传给algoClOrdId
- */
- private String attachAlgoClOrdId;
- /**
- * 可选 止盈触发价
- * 对于条件止盈单,如果填写此参数,必须填写 止盈委托价
- */
- private String tpTriggerPx;
- /**
- * 可选 止盈委托价
- * 对于条件止盈单,如果填写此参数,必须填写 止盈触发价
- * 对于限价止盈单,需填写此参数,不需要填写止盈触发价
- * 委托价格为-1时,执行市价止盈
- */
- private String tpOrdPx;
- /**
- * 否 止盈订单类型
- * condition: 条件单
- * limit: 限价单
- * 默认为condition
- */
- private String tpOrdKind;
- /**
- * 可选 止损触发价,如果填写此参数,必须填写 止损委托价
- */
- private String slTriggerPx;
- /**
- * String 可选 止损委托价,如果填写此参数,必须填写 止损触发价
- * 委托价格为-1时,执行市价止损
- */
- private String slOrdPx;
- /**
- * 否 止盈触发价类型
- * last:最新价格
- * index:指数价格
- * mark:标记价格
- * 默认为last
- */
- private String tpTriggerPxType;
- /**
- * 否 止损触发价类型
- * last:最新价格
- * index:指数价格
- * mark:标记价格
- * 默认为last
- */
- private String slTriggerPxType;
- /**
- * 否 是否启用开仓价止损,仅适用于分批止盈的止损订单,第一笔止盈触发时,止损触发价格是否移动到开仓均价止损
- * 0:不开启,默认值
- * 1:开启,且止损触发价不能为空
- */
- private String amendPxOnTriggerType;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/TradeOrderDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/TradeOrderDto.java
deleted file mode 100644
index b11b8ba..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/Dto/TradeOrderDto.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto;
-
-import io.swagger.annotations.ApiModel;
-import lombok.Data;
-
-/**
- * @author wzy
- * @date 2021-09-16
- **/
-@Data
-@ApiModel(value = "TradeOrderDto", description = "交易订单参数接收类")
-public class TradeOrderDto {
- private String instrumentId;
- private String side;
- private String type;
- private String size;
- private String price;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeInfoEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeInfoEnum.java
deleted file mode 100644
index 8aab481..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeInfoEnum.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config;
-
-import lombok.Getter;
-
-/**
- * 交易信息枚举类
- * 用于存储不同交易账户的密钥信息,包括实盘账户和模拟账户
- */
-@Getter
-public enum ExchangeInfoEnum {
-
- /**
- * 模拟盘账户信息
- * 存储了模拟盘交易所需的API密钥、秘钥和通过码
- */
-// OKX_UAT("f512673b-2685-4fcb-9bb1-2ae8db745d62",
-// "B0C1CC8F39625B41140D93DC25039E33",
-// "Aa12345678@",
-// true);
- OKX_UAT("ffb4e79f-fcf5-4afb-82c5-2fbb64123f61",
- "AA06C5ED1D7C7F5AFE6484052E231C55",
- "Aa12345678@",
- false);
-
-// /**
-// * 模拟盘账户信息
-// * 存储了模拟盘交易所需的API密钥、秘钥和通过码
-// */
-// OKX_UAT("0769b50c-2c36-4310-8bd9-cad6bc6c9d8f",
-// "7AF4A574BC44907CE76BBFF91F53852D",
-// "Aa123456@",
-// false);
-
- // API公钥,用于识别用户身份
- private String apiKey;
-
- // API秘钥,用于签名和验证请求
- private String secretKey;
-
- // API通过码,用于额外的身份验证
- private String passphrase;
-
- // 账户类型,true表示实盘账户,false表示模拟账户
- private boolean accountType;
-
- /**
- * 构造方法
- *
- * @param apiKey API公钥,用于识别用户身份
- * @param secretKey API秘钥,用于签名和验证请求
- * @param passphrase API通过码,用于额外的身份验证
- * @param accountType 账户类型,true表示实盘账户,false表示模拟账户
- */
- ExchangeInfoEnum(String apiKey, String secretKey, String passphrase, boolean accountType) {
- this.apiKey = apiKey;
- this.secretKey = secretKey;
- this.passphrase = passphrase;
- this.accountType = accountType;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeLoginEventService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeLoginEventService.java
deleted file mode 100644
index b4d7b33..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeLoginEventService.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.SubmitOrderReqDto;
-
-import java.util.LinkedHashMap;
-
-public interface ExchangeLoginEventService {
- /**
- * 获取交易产品基础信息
- * 获取所有可交易产品的信息列表。
- * <br><br>
- * GET /api/v5/public/instruments /api/v5/account/instruments
- * <br>
- *
- * @param parameters LinkedHashedMap of String,Object pair
- * where String is the name of the parameter and Object is the value of the parameter
- * <br><br>
- * instType -- String 是 产品类型 SPOT:币币 MARGIN:币币杠杆 SWAP:永续合约 FUTURES:交割合约 OPTION:期权 <br>
- * uly -- String 可选 标的指数,仅适用于交割/永续/期权,期权必填 <br>
- * instFamily -- String 否 交易品种,仅适用于交割/永续/期权 <br>
- * instId -- String 否 产品ID <br>
- * @return String
- * @see <a href="https://www.okx.com/docs-v5/zh/#rest-api-public-data-get-instruments">
- * https://www.okx.com/docs-v5/zh/#rest-api-public-data-get-instruments</a>
- */
- String exchangeInfo(LinkedHashMap<String, Object> parameters);
-
- String lineHistory(LinkedHashMap<String, Object> parameters);
- /**
- * 查看账户余额
- * 获取交易账户中资金余额信息。
- * <br><br>
- * GET /api/v5/account/balance
- * <br>
- * @param
- * parameters LinkedHashedMap of String,Object pair
- * where String is the name of the parameter and Object is the value of the parameter
- * <br><br>
- * ccy -- String 否 币种,如 BTC 支持多币种查询(不超过20个),币种之间半角逗号分隔 <br>
- * @return String
- * @see <a href="https://www.okx.com/docs-v5/zh/#rest-api-account-get-balance">
- * https://www.okx.com/docs-v5/zh/#rest-api-account-get-balance</a>
- */
- String balance(LinkedHashMap<String, Object> parameters);
- /**
- * 查看持仓信息
- * 获取该账户下拥有实际持仓的信息。账户为单向持仓模式会显示净持仓(net),账户为双向持仓模式下会分别返回多头(long)或空头(short)的仓位。按照仓位创建时间倒序排列。
- * <br><br>
- * GET /api/v5/account/positions
- * <br>
- * @param
- * parameters LinkedHashedMap of String,Object pair
- * where String is the name of the parameter and Object is the value of the parameter
- * <br><br>
- * instType -- String 否 产品类型
- * MARGIN:币币杠杆
- * SWAP:永续合约
- * FUTURES:交割合约
- * OPTION:期权
- * instType和instId同时传入的时候会校验instId与instType是否一致。<br>
- * instId -- String 否 交易产品ID,如:BTC-USD-190927-5000-C
- * 支持多个instId查询(不超过10个),半角逗号分隔<br>
- * posId -- String 否 持仓ID
- * 支持多个posId查询(不超过20个),半角逗号分割<br>
- * @return String <br>
- * note: 如果该 instId 拥有过仓位且当前持仓量为0,传 instId 时,会返回仓位信息;不传 instId 时,仓位信息不返回。
- * 逐仓交易设置中,如果设置为自主划转模式,逐仓转入保证金后,会生成一个持仓量为0的仓位 <br>
- * @see <a href="https://www.okx.com/docs-v5/zh/#rest-api-account-get-positions">
- * https://www.okx.com/docs-v5/zh/#rest-api-account-get-positions</a>
- */
- String positions(LinkedHashMap<String, Object> parameters);
- /**
- * 查看历史持仓信息
- * 获取最近3个月有更新的仓位信息,按照仓位更新时间倒序排列。
- * <br><br>
- * GET /api/v5/account/positions-history
- * <br>
- * @param
- * parameters LinkedHashedMap of String,Object pair
- * where String is the name of the parameter and Object is the value of the parameter
- * <br><br>
- * instType -- String 否 产品类型
- * MARGIN:币币杠杆
- * SWAP:永续合约
- * FUTURES:交割合约
- * OPTION:期权 <br>
- * instId -- String 否 交易产品ID,如:BTC-USD-SWAP <br>
- * mgnMode -- String 否 保证金模式
- * cross:全仓,isolated:逐仓
- * type -- String 否 平仓类型
- * 1:部分平仓;2:完全平仓;3:强平;4:强减; 5:ADL自动减仓;
- * 状态叠加时,以最新的平仓类型为准状态为准。 <br>
- * posId -- String 否 持仓ID <br>
- * after -- String 否 查询仓位更新 (uTime) 之前的内容,值为时间戳,Unix 时间戳为毫秒数格式,如 1597026383085 <br>
- * before -- String 否 查询仓位更新 (uTime) 之后的内容,值为时间戳,Unix 时间戳为毫秒数格式,如 1597026383085 <br>
- * limit -- String 否 分页返回结果的数量,最大为100,默认100条 <br>
- * @return String
- * @see <a href="https://www.okx.com/docs-v5/zh/#rest-api-account-get-positions-history">
- * https://www.okx.com/docs-v5/zh/#rest-api-account-get-positions-history</a>
- */
- String positionsHistory(LinkedHashMap<String, Object> parameters);
- /**
- * 撤单
- * 撤销之前下的未完成订单。
- *
- * <br><br>
- * GET /api/v5/trade/cancel-order
- * <br>
- *
- * @param originOrderId 用户自定义ID
- * LinkedHashedMap of String,Object pair
- * where String is the name of the parameter and Object is the value of the parameter
- * <br><br>
- * instId -- String 是 产品ID,如 BTC-USD-190927 <br>
- * ordId -- String 可选 订单ID, ordId和clOrdId必须传一个,若传两个,以ordId为主 <br>
- * clOrdId -- String 可选 用户自定义ID <br>
- * @return String
- * @see <a href="https://www.okx.com/docs-v5/zh/#rest-api-trade-cancel-order">
- * https://www.okx.com/docs-v5/zh/#rest-api-trade-cancel-order</a>
- */
- boolean cancelOrder(String originOrderId,String instId);
- /**
- * 下单
- * 只有当您的账户有足够的资金才能下单。
- *
- * <br><br>
- * GET /api/v5/trade/order
- * <br>
- *
- * @param submitOrderReq
- * LinkedHashedMap of String,Object pair
- * where String is the name of the parameter and Object is the value of the parameter
- * <br><br>
- * instId -- String 是 产品ID,如 BTC-USD-190927-5000-C <br>
- * tdMode -- String 是 交易模式
- * 保证金模式:isolated:逐仓 ;cross:全仓
- * 非保证金模式:cash:非保证金 <br>
- * ccy -- String 否 保证金币种,仅适用于单币种保证金模式下的全仓杠杆订单 <br>
- * clOrdId -- String 否 客户自定义订单ID
- * 字母(区分大小写)与数字的组合,可以是纯字母、纯数字且长度要在1-32位之间。<br>
- * tag -- String 否 订单标签
- * 字母(区分大小写)与数字的组合,可以是纯字母、纯数字,且长度在1-16位之间。 <br>
- * side -- String 是 订单方向
- * buy:买, sell:卖 <br>
- * posSide -- String 可选 持仓方向
- * 在双向持仓模式下必填,且仅可选择 long 或 short。 仅适用交割、永续。 <br>
- * ordType -- String 是 订单类型
- * market:市价单
- * limit:限价单
- * post_only:只做maker单
- * fok:全部成交或立即取消
- * ioc:立即成交并取消剩余
- * optimal_limit_ioc:市价委托立即成交并取消剩余(仅适用交割、永续) <br>
- * sz -- String 是 委托数量 <br>
- * px -- String 可选 委托价格,仅适用于limit、post_only、fok、ioc类型的订单 <br>
- * reduceOnly -- Boolean 否 是否只减仓,true 或 false,默认false
- * 仅适用于币币杠杆,以及买卖模式下的交割/永续
- * 仅适用于单币种保证金模式和跨币种保证金模式 <br>
- * tgtCcy -- String 否 市价单委托数量sz的单位,仅适用于币币市价订单
- * base_ccy: 交易货币 ;quote_ccy:计价货币
- * 买单默认quote_ccy, 卖单默认base_ccy <br>
- * banAmend -- Boolean 否 是否禁止币币市价改单,true 或 false,默认false
- * 为true时,余额不足时,系统不会改单,下单会失败,仅适用于币币市价单 <br>
- * tpTriggerPx -- String 否 止盈触发价,如果填写此参数,必须填写 止盈委托价 <br>
- * tpOrdPx -- String 否 止盈委托价,如果填写此参数,必须填写 止盈触发价
- * 委托价格为-1时,执行市价止盈 <br>
- * slTriggerPx -- String 否 止损触发价,如果填写此参数,必须填写 止损委托价 <br>
- * slOrdPx -- String 否 止损委托价,如果填写此参数,必须填写 止损触发价
- * 委托价格为-1时,执行市价止损 <br>
- * tpTriggerPxType -- String 否 止盈触发价类型
- * last:最新价格
- * index:指数价格
- * mark:标记价格
- * 默认为last <br>
- * slTriggerPxType -- String 否 止损触发价类型
- * last:最新价格
- * index:指数价格
- * mark:标记价格
- * 默认为last <br>
- * @return String
- * @see <a href="https://www.okx.com/docs-v5/zh/#rest-api-trade-place-order">
- * https://www.okx.com/docs-v5/zh/#rest-api-trade-place-order</a>
- */
- String submitOrder(SubmitOrderReqDto submitOrderReq);
-
- /**
- * 获取单个币种价格信息
- * @param parameters
- * @return
- */
- String tickerMess(LinkedHashMap<String, Object> parameters);
-
- /**
- * 获取单个订单信息
- * @param parameters
- * @return
- */
- public String getOrderMessage(LinkedHashMap<String, Object> parameters);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeLoginService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeLoginService.java
deleted file mode 100644
index 20ff07a..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ExchangeLoginService.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config;
-
-
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.impl.ExchangeLoginEventServiceImpl;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 交易所登录服务 singleton模式
- * 负责根据交易所类型提供对应的交易所登录事件服务
- */
-public class ExchangeLoginService {
- // 存储交易所类型与登录服务实例的映射
- private final static Map<String, ExchangeLoginEventService> eventMap = new HashMap<>();
-
- // 静态代码块,用于初始化eventMap
- static {
- for (ExchangeInfoEnum infoEnum : ExchangeInfoEnum.values()) {
- eventMap.put(infoEnum.name(), new ExchangeLoginEventServiceImpl(
- infoEnum.getApiKey(),
- infoEnum.getSecretKey(),
- infoEnum.getPassphrase(),
- infoEnum.isAccountType()));
- }
- }
-
- // 私有构造方法,防止外部实例化
- private ExchangeLoginService() {
- }
-
- // Singleton实例
- public final static ExchangeLoginService INSTANCE = new ExchangeLoginService();
-
- /**
- * 根据交易所类型获取对应的交易所登录事件服务
- * @param exchangeType 交易所类型
- * @return 对应的交易所登录事件服务实例
- * @throws FebsException 如果提供的交易所类型无效,则抛出异常
- */
- public static ExchangeLoginEventService getInstance(String exchangeType) {
- ExchangeLoginEventService exchange = eventMap.get(exchangeType);
- if (exchange == null) {
- throw new FebsException("参数错误");
- }
-
- return exchange;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java
index fbf5f94..17c0d82 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java
@@ -1,7 +1,7 @@
package com.xcong.excoin.modules.okxNewPrice.okxpi.config;
import com.alibaba.fastjson.JSON;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.FebsException;
import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.RequestType;
import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.DateUtils;
@@ -83,6 +83,7 @@
queryString = UrlBuilder.buildFullUrl(urlPath,"" , parameters, null);
// queryString = UrlBuilder.buildFullUrl(null, urlPath, parameters, null);
}
+
String sign = SignUtils.signRest(secretKey,
timestamp,
httpMethod.toString(),
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ResponseHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ResponseHandler.java
index 3ef2c50..2e124e3 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ResponseHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/ResponseHandler.java
@@ -1,7 +1,7 @@
package com.xcong.excoin.modules.okxNewPrice.okxpi.config;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.FebsException;
import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.JSONParser;
import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OkHttpUtils;
import okhttp3.Request;
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/impl/ExchangeLoginEventServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/impl/ExchangeLoginEventServiceImpl.java
deleted file mode 100644
index 3d781ed..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/impl/ExchangeLoginEventServiceImpl.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.impl;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.SubmitOrderReqDto;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.ExchangeInfoEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.ExchangeLoginEventService;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.ExchangeLoginService;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.DefaultUrls;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OKXContants;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.*;
-
-@Slf4j
-public class ExchangeLoginEventServiceImpl implements ExchangeLoginEventService {
-
-
- private OKXAccount OKXAccount;
- private String apiKey;
- private String secretKey;
- private String passphrase;
- private boolean accountType;
-
- public ExchangeLoginEventServiceImpl(String apiKey, String secretKey, String passphrase, boolean accountType) {
- this.apiKey = apiKey;
- this.secretKey = secretKey;
- this.passphrase = passphrase;
- this.accountType = accountType;
- OKXAccount = new OKXAccount(
- accountType ? DefaultUrls.USDM_PROD_URL : DefaultUrls.USDM_UAT_URL,
- apiKey,
- secretKey,
- passphrase,
- !accountType);
- }
-
- @Override
- public String exchangeInfo(LinkedHashMap<String, Object> parameters) {
- return OKXAccount.requestHandler.sendPublicRequest(OKXAccount.baseUrl, OKXContants.INSTRUMENTS,parameters, HttpMethod.GET, OKXAccount.isSimluate());
- }
-
- @Override
- public String lineHistory(LinkedHashMap<String, Object> parameters) {
- return OKXAccount.requestHandler.sendPublicRequest(OKXAccount.baseUrl, OKXContants.K_LINE_HISTORY,parameters, HttpMethod.GET, OKXAccount.isSimluate());
- }
-
- @Override
- public String balance(LinkedHashMap<String, Object> parameters) {
- return OKXAccount.requestHandler.sendSignedRequest(OKXAccount.baseUrl, OKXContants.BALANCE, parameters, HttpMethod.GET, OKXAccount.isSimluate());
- }
-
- @Override
- public String positions(LinkedHashMap<String, Object> parameters) {
- return OKXAccount.requestHandler.sendSignedRequest(OKXAccount.baseUrl, OKXContants.POSITIONS, parameters, HttpMethod.GET, OKXAccount.isSimluate());
- }
-
- @Override
- public String positionsHistory(LinkedHashMap<String, Object> parameters) {
- return OKXAccount.requestHandler.sendSignedRequest(OKXAccount.baseUrl, OKXContants.POSITIONS_HISTORY, parameters, HttpMethod.GET, OKXAccount.isSimluate());
- }
-
- @Override
- public boolean cancelOrder(String originOrderId,String instId) {
- LinkedHashMap<String, Object> parameters = new LinkedHashMap<>();
- parameters.put("instId", instId);
- parameters.put("clOrdId", originOrderId);
-
- String s = OKXAccount.requestHandler.sendSignedRequest(OKXAccount.baseUrl, OKXContants.CANCEL_ORDER, parameters, HttpMethod.POST, OKXAccount.isSimluate());
- log.info("[{}] 收到撤单请求,返回", s);
- return true;
- }
-
- @Override
- public String submitOrder(SubmitOrderReqDto submitOrderReq) {
- log.info("收到下单请求,参数:[{}]", submitOrderReq);
- LinkedHashMap<String, Object> parameters = new LinkedHashMap<>();
-
- String side = submitOrderReq.getSide();
- String type = submitOrderReq.getOrdType();
- String positionSides = submitOrderReq.getPosSide();
- // 开仓
- //开多:买多BUY、LONG
- //开空:卖空SELL、SHORT
- if ("buy".equals(side)) {
- if ("limit".equals(type)) {
- parameters.put("px", submitOrderReq.getPx());
- parameters.put("ordType", "limit");
- }
- // 持仓方向
- parameters.put("posSide", positionSides);
- //placeOrderReq.setPosSide(positionSide);
- // slTriggerPx 止损触发价,如果填写此参数,必须填写 止损委托价
- // slOrdPx 止损委托价,如果填写此参数,必须填写 止损触发价
-
- if (new BigDecimal(submitOrderReq.getSlTriggerPx()).compareTo(BigDecimal.ZERO) > 0) {
- Map<String, Object> attachAlgoOrder = new HashMap<>();
- // 如果是开多 止损价小于传来的价格
-
- List<Map<String, Object>> attachAlgoOrds = new ArrayList<>();
- // 如果是开空 止损价小于传来的价格
- attachAlgoOrder.put("slTriggerPx", submitOrderReq.getSlTriggerPx());
- attachAlgoOrder.put("slOrdPx", submitOrderReq.getSlOrdPx());
- attachAlgoOrds.add(attachAlgoOrder);
- parameters.put("attachAlgoOrds", attachAlgoOrds);
- } else {
- BigDecimal price = new BigDecimal(submitOrderReq.getPrice());
- BigDecimal stopPrice = BigDecimal.ZERO;
- if ("buy".equalsIgnoreCase(side)) {
- stopPrice = price.multiply(new BigDecimal("0.99")).setScale(2,BigDecimal.ROUND_DOWN);
- } else {
- stopPrice = price.multiply(new BigDecimal("1.01")).setScale(2,BigDecimal.ROUND_DOWN);
- }
- Map<String, Object> attachAlgoOrder = new HashMap<>();
- // 如果是开多 止损价小于传来的价格
- List<Map<String, Object>> attachAlgoOrds = new ArrayList<>();
- // 如果是开空 止损价小于传来的价格
- attachAlgoOrder.put("slTriggerPx", stopPrice);
- attachAlgoOrder.put("slOrdPx", stopPrice);
- attachAlgoOrds.add(attachAlgoOrder);
- parameters.put("attachAlgoOrds", attachAlgoOrds);
- }
- } else {
- // 平仓
- //平空:卖空BUY、SHORT
- //平多:卖多SELL、LONG
- //side = (CoreEnum.DirectionEnum.D_Buy.getNumber() == direction.getNumber()) ? "BUY" : "SELL";
- // 平仓方向
- //positionSide = (CoreEnum.DirectionEnum.D_Buy.getNumber() == direction.getNumber()) ? "SHORT" : "LONG";
- if ("limit".equals(type)) {
- //placeOrderReq.setPx(new BigDecimal(submitOrderReq.price()));
- parameters.put("px", submitOrderReq.getPrice());
- //parameters.put("timeInForce", timeInForce);
- }
- //placeOrderReq.setPosSide(positionSide);
- parameters.put("posSide", positionSides);
- }
-
- //订单种类,市价单不传价格
- parameters.put("instId", submitOrderReq.getInstId());
- parameters.put("side", side);
- //placeOrderReq.setSide(side);
- parameters.put("ordType", type);
- //placeOrderReq.setSz(new BigDecimal(quantity));
- parameters.put("sz", submitOrderReq.getSz());
- //placeOrderReq.setClOrdId(submitOrderReq.originOrderId());
- parameters.put("clOrdId", submitOrderReq.getClOrdId());
- parameters.put("tdMode", submitOrderReq.getTdMode());
- log.info("下单参数:[{}]",JSON.toJSONString(parameters));
- String placeOrderRspOkxRestResponse = OKXAccount.requestHandler.sendSignedRequest(OKXAccount.baseUrl, OKXContants.ORDER, parameters, HttpMethod.POST, OKXAccount.isSimluate());
- log.info("收到下单返回,响应:[{}]", JSON.parseObject(placeOrderRspOkxRestResponse).get("data"));
- return submitOrderReq.getClOrdId();
- }
-
- @Override
- public String tickerMess(LinkedHashMap<String, Object> parameters) {
- return OKXAccount.requestHandler.sendSignedRequest(OKXAccount.baseUrl, OKXContants.TICKER, parameters, HttpMethod.GET, OKXAccount.isSimluate());
- }
-
- @Override
- public String getOrderMessage(LinkedHashMap<String, Object> parameters) {
- return OKXAccount.requestHandler.sendSignedRequest(OKXAccount.baseUrl, OKXContants.TICKER, parameters, HttpMethod.GET, OKXAccount.isSimluate());
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/FebsException.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/FebsException.java
new file mode 100644
index 0000000..3ed3f38
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/FebsException.java
@@ -0,0 +1,15 @@
+package com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils;
+
+/**
+ * OKX 系统内部异常。
+ *
+ * @author MrBird
+ */
+public class FebsException extends RuntimeException {
+
+ private static final long serialVersionUID = -994962710559017255L;
+
+ public FebsException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/ParameterChecker.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/ParameterChecker.java
deleted file mode 100644
index 1eec770..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/ParameterChecker.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils;
-
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
-
-import java.util.LinkedHashMap;
-
-public final class ParameterChecker {
-
- private ParameterChecker() {
- }
-
- public static void checkParameter(LinkedHashMap<String, Object> parameters, String parameter, Class t) {
- checkRequiredParameter(parameters, parameter);
- checkParameterType(parameters.get(parameter), t, parameter);
- }
-
- public static void checkOrParameters(LinkedHashMap<String, Object> parameters, String parameter, String parameter2) {
- if (!parameters.containsKey(parameter) && (!parameters.containsKey(parameter2))) {
- throw new FebsException(String.format("Either \"%s\" or \"%s\" is required!", parameter, parameter2));
- }
- }
-
- public static void checkRequiredParameter(LinkedHashMap<String, Object> parameters, String parameter) {
- if (!parameters.containsKey(parameter)) {
- throw new FebsException(String.format("\"%s\" is a mandatory parameter!", parameter));
- }
- }
-
- public static void checkParameterType(Object parameter, Class t, String name) {
- if (!t.isInstance(parameter)) {
- throw new FebsException(String.format("\"%s\" must be of %s type.", name, t));
- } else if (t == String.class && parameter.toString().trim().equals("")) {
- throw new FebsException(String.format("\"%s\" must not be empty.", name));
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/RequestBuilder.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/RequestBuilder.java
index e887de5..30bf027 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/RequestBuilder.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/RequestBuilder.java
@@ -1,7 +1,7 @@
package com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
+import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.FebsException;
import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
import okhttp3.MediaType;
import okhttp3.Request;
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/SSLConfig.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/SSLConfig.java
new file mode 100644
index 0000000..1a7fad6
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/utils/SSLConfig.java
@@ -0,0 +1,22 @@
+package com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import java.security.SecureRandom;
+
+/**
+ * SSL 配置工具。
+ *
+ * @author Administrator
+ */
+public class SSLConfig {
+ public static void configureSSL() {
+ try {
+ SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
+ sslContext.init(null, null, new SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/BalanceVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/BalanceVo.java
deleted file mode 100644
index b81bebb..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/BalanceVo.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.vo;
-
-import lombok.Data;
-
-@Data
-public class BalanceVo {
- //币种 如BTC
- private String ccy;
- // 可用余额
- private String availBal;
- // 币种余额
- private String cashBal;
- // 可用保证金
- private String availEq;
- // 未实现盈亏总额
- private String unrealizedProfit;
- // 维持保证金
- private String maintMargin;
- //合约率
- private String mgnRatio;
- //占用保证金
- private String frozenBal;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/InstrumentsVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/InstrumentsVo.java
deleted file mode 100644
index 9cd7358..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/InstrumentsVo.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.vo;
-
-import lombok.Data;
-
-@Data
-public class InstrumentsVo {
- /**
- * 产品id, 如 BTC-USDT
- */
- private String instId;
- /**
- * 产品状态
- * live:交易中
- * suspend:暂停中
- * preopen:预上线,如:交割和期权的新合约在 live 之前,会有 preopen 状态
- * test:测试中(测试产品,不可交易)
- */
- private String state;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/PositionsVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/PositionsVo.java
deleted file mode 100644
index f331032..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/vo/PositionsVo.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.config.vo;
-
-import com.alibaba.fastjson.JSONObject;
-import lombok.Data;
-
-import java.util.List;
-import java.util.Map;
-
-@Data
-public class PositionsVo {
- private List<JSONObject> positionList;
- private Map<String, JSONObject> newPositionMap;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/enumerates/TradeTypeEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/enumerates/TradeTypeEnum.java
deleted file mode 100644
index 07fddf7..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/enumerates/TradeTypeEnum.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.enumerates;
-
-import lombok.Getter;
-
-@Getter
-public enum TradeTypeEnum {
- /**
- * 1 - 开仓 2 - 平仓
- */
- OPEN_ORDER(1,"open","开仓"),
- CLOSE_ORDER(2,"close","平仓"),
- /**
- * 交易模式
- * 保证金模式:isolated:逐仓 ;cross:全仓
- * 非保证金模式:cash:非保证金
- * spot_isolated:现货逐仓(仅适用于现货带单) ,现货带单时,tdMode 的值需要指定为spot_isolated
- */
- ISOLATED(1,"isolated","逐仓"),
- CROSS(2,"cross","全仓"),
- /**
- * 持仓方向
- * long:开平仓模式开多,pos为正
- * short:开平仓模式开空,pos为正
- * net:买卖模式(交割/永续/期权:pos为正代表开多,pos为负代表开空。币币杠杆时,pos均为正,posCcy为交易货币时,代表开多;posCcy为计价货币时,代表开空。)
- */
- LONG(1,"long","持仓方向-long"),
- SHORT(2,"short","持仓方向-short"),
- /**
- * 订单类型
- * market:市价单
- * limit:限价单
- * post_only:只做maker单
- * fok:全部成交或立即取消
- * ioc:立即成交并取消剩余
- * optimal_limit_ioc:市价委托立即成交并取消剩余(仅适用交割、永续)
- * mmp:做市商保护(仅适用于组合保证金账户模式下的期权订单)
- * mmp_and_post_only:做市商保护且只做maker单(仅适用于组合保证金账户模式下的期权订单)
- */
- MARKET(1,"market","市价单"),
- LIMIT(2,"limit","限价单"),
- /**
- * 订单方向
- * buy:买, sell:卖
- */
- BUY(1,"buy","买"),
- SELL(2,"sell","卖")
- ;
-
- private int code;
- private String value;
- private String description;
-
- TradeTypeEnum(int code, String value, String description) {
- this.code = code;
- this.value = value;
- this.description = description;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/ITradeOrderService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/ITradeOrderService.java
deleted file mode 100644
index f18ddb8..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/ITradeOrderService.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.order;
-
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsResponse;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.TradeOrderDto;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestBuy;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestSell;
-
-//订单交易接口 欧易调用的接口是 撮合交易/交易/ POST 下单
-public interface ITradeOrderService {
- FebsResponse QuantExchangeReturnVo(TradeOrderDto tradeOrderDto, QuantApiMessage quantApiMessage);
-
- /**
- * 消费买入消息
- * @param returnVo
- */
- void operationBuyMsg(TradeRequestBuy returnVo);
-
- /**
- * 消费卖出消息
- * @param returnVo
- */
- void operationSellMsg(TradeRequestSell returnVo);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/TradeOrderFactory.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/TradeOrderFactory.java
deleted file mode 100644
index 9736802..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/TradeOrderFactory.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.order;
-
-import lombok.Data;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Component;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 交易订单工厂类
- * 该类用于根据不同的交易平台(如OKX、BINANCE)获取相应的交易订单服务实例
- */
-@Component
-@Data
-public class TradeOrderFactory {
- /**
- * OKX交易平台的交易订单服务实例
- */
- @Qualifier("oKXTradeOrderServiceImpl")
- private final ITradeOrderService oKXTradeOrderServiceImpl;
-
- /**
- * 存储不同交易平台对应的交易订单服务实例的映射
- */
- private Map<String, ITradeOrderService> accountMap = new HashMap<>();
-
- /**
- * 构造方法,初始化交易平台与交易订单服务实例的映射
- *
- * @param oKXTradeOrderServiceImpl OKX交易平台的交易订单服务实例
- */
- public TradeOrderFactory(ITradeOrderService oKXTradeOrderServiceImpl) {
- this.oKXTradeOrderServiceImpl = oKXTradeOrderServiceImpl;
- accountMap.put("OKX", oKXTradeOrderServiceImpl);
- }
-
- /**
- * 根据平台关键字获取交易订单服务实例
- *
- * @param key 平台关键字,如"OKX"、"BINANCE"
- * @return 对应平台的交易订单服务实例
- */
- public ITradeOrderService get(String key) {
- return accountMap.get(key);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/impl/OKXTradeOrderServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/impl/OKXTradeOrderServiceImpl.java
deleted file mode 100644
index 7832be2..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/impl/OKXTradeOrderServiceImpl.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.order.impl;
-
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsResponse;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.TradeOrderDto;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.order.ITradeOrderService;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.order.vo.QuantExchangeReturnVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestBuy;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeRequestSell;
-import com.xcong.excoin.modules.okxNewPrice.jiaoyi.IMQService;
-import lombok.SneakyThrows;
-import org.json.JSONObject;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Base64;
-
-@Service("oKXTradeOrderServiceImpl")
-public class OKXTradeOrderServiceImpl implements ITradeOrderService {
- @Value("${spring.OKEX.baseurl}")
- private String baseurl;
-
- @Resource
- private IMQService imqService;
-
- @SneakyThrows
- @Override
- public FebsResponse QuantExchangeReturnVo(TradeOrderDto tradeOrderDto, QuantApiMessage quantApiMessage) {
- try {
- // 构建订单的JSON对象
- JSONObject jsonBody = new JSONObject();
- jsonBody.put("instId", "BTC-USDT");
- jsonBody.put("tdMode", "cash");
- jsonBody.put("side", "buy");
- jsonBody.put("ordType", "limit");
- jsonBody.put("sz", "0.01");
- jsonBody.put("px", "30000");
-
- // 发起下单请求
- String result = postRequest("/api/v5/trade/order", jsonBody.toString(),quantApiMessage);
- System.out.println("Result: " + result);
-
- //解析返回数据
- JSONObject jsonResponse = new JSONObject(result);
- if (jsonResponse.has("code") && "0".equals(jsonResponse.getString("code"))) {
- // 订单提交成功
- JSONObject jSONObject = jsonResponse.getJSONObject("data");
- String clOrdId = jSONObject.getString("clOrdId");
- String ordId = jSONObject.getString("ordId");
- QuantExchangeReturnVo quantExchangeReturnVo = new QuantExchangeReturnVo();
- quantExchangeReturnVo.setCode("0");
- quantExchangeReturnVo.setOrdId(ordId);
- quantExchangeReturnVo.setClOrdId(clOrdId);
- return new FebsResponse().success().data(quantExchangeReturnVo);
- } else {
- String code = jsonResponse.getString("code");
- String msg = jsonResponse.getString("msg");
- QuantExchangeReturnVo quantExchangeReturnVo = new QuantExchangeReturnVo();
- quantExchangeReturnVo.setCode(code);
- quantExchangeReturnVo.setMessage(msg);
- return new FebsResponse().fail().data(quantExchangeReturnVo);
- }
-
- } catch (Exception e) {
- return new FebsResponse().fail().message("下单失败");
- }
- }
-
- @Override
- public void operationBuyMsg(TradeRequestBuy returnVo) {
-
- imqService.operationBuyMsg(returnVo);
- }
-
- @Override
- public void operationSellMsg(TradeRequestSell returnVo) {
-
- imqService.operationSellMsg(returnVo);
- }
-
- private String postRequest(String endpoint, String body, QuantApiMessage quantApiMessage) throws Exception {
- URL url = new URL(baseurl + endpoint);
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setDoOutput(true);
- connection.setRequestMethod("POST");
- connection.setRequestProperty("Content-Type", "application/json");
- connection.setRequestProperty("OK-ACCESS-KEY", quantApiMessage.getASecretkey());
- connection.setRequestProperty("OK-ACCESS-SIGN", generateSignature(body,quantApiMessage));
- connection.setRequestProperty("OK-ACCESS-TIMESTAMP", getTimestamp());
- connection.setRequestProperty("OK-ACCESS-PASSPHRASE", quantApiMessage.getPassPhrass());
-
- try (OutputStream os = connection.getOutputStream()) {
- os.write(body.getBytes());
- os.flush();
- }
-
- if (connection.getResponseCode() != 200) {
- throw new RuntimeException("Failed : HTTP Error code : " + connection.getResponseCode());
- }
-
- BufferedReader br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
- StringBuilder output = new StringBuilder();
- String line;
- while ((line = br.readLine()) != null) {
- output.append(line);
- }
- connection.disconnect();
- return output.toString();
- }
-
- private static String generateSignature(String body, QuantApiMessage quantApiMessage) throws Exception {
- String preHash = getTimestamp() + "POST" + "/api/v5/order" + body;
- SecretKeySpec secretKey = new SecretKeySpec(quantApiMessage.getBSecretkey().getBytes(), "HmacSHA256");
- Mac mac = Mac.getInstance("HmacSHA256");
- mac.init(secretKey);
- return Base64.getEncoder().encodeToString(mac.doFinal(preHash.getBytes()));
- }
-
- private static String getTimestamp() {
- return String.valueOf(System.currentTimeMillis() / 1000);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/vo/QuantExchangeReturnVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/vo/QuantExchangeReturnVo.java
deleted file mode 100644
index 280fe02..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/order/vo/QuantExchangeReturnVo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.order.vo;
-
-import lombok.Data;
-
-/**
- * 订单返回信息
- */
-@Data
-public class QuantExchangeReturnVo{
-
- private String code;//交易状态 0代表成功
- private String message;//错误信息
- private String ordId;//交易所订单号
- private String clOrdId;//客户订单id
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/IQueryOrderService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/IQueryOrderService.java
deleted file mode 100644
index 225d64f..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/IQueryOrderService.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.query;
-
-
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsResponse;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.query.dto.QuantOperateRecode;
-
-//订单查询接口 欧易调用的接口是 撮合交易/交易/ GET 获取订单信息
-public interface IQueryOrderService {
- FebsResponse QueryOrder(QuantApiMessage quantApiMessage, String instId, String clOrdId);
-
- //检查订单在交易所交易情况 exChangeState返回状态说明 1.filled代表交易成功 2.canceled代表交易失败或者取消 3.live代表交易中
- FebsResponse checkOrder(QuantOperateRecode operateRecode);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/QueryOrderFactory.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/QueryOrderFactory.java
deleted file mode 100644
index 0bd1ac6..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/QueryOrderFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.query;
-
-import lombok.Data;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Component;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 查询委托工厂类
- * 该类用于根据不同的交易平台(如OKX、BINANCE)获取相应的查询委托服务实例
- */
-@Component
-@Data
-public class QueryOrderFactory {
- // OKX的查询委托服务实现
- @Qualifier("oKXQueryOrderServiceImpl")
- private final IQueryOrderService oKXQueryOrderServiceImpl;
-
- // 存储不同交易平台查询委托服务的映射
- private Map<String, IQueryOrderService> accountMap = new HashMap<>();
-
- /**
- * 构造方法,初始化查询委托服务映射
- * @param oKXQueryOrderServiceImpl OKX的查询委托服务实现
- */
- public QueryOrderFactory(IQueryOrderService oKXQueryOrderServiceImpl) {
- this.oKXQueryOrderServiceImpl = oKXQueryOrderServiceImpl;
- accountMap.put("OKX", oKXQueryOrderServiceImpl);
- }
-
- /**
- * 根据平台名称获取查询委托服务实例
- * @param key 平台名称,如"OKX"、"BINANCE"
- * @return 对应平台的查询委托服务实例
- */
- public IQueryOrderService get(String key) {
- return accountMap.get(key);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/dto/QuantOperateRecode.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/dto/QuantOperateRecode.java
deleted file mode 100644
index 27d525e..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/dto/QuantOperateRecode.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.query.dto;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Data
-public class QuantOperateRecode{
-
- private String tradeNumber;//交易编号
- private String operationCode;//操作编号
- private String sellTradeNumber;//卖出的订单号
- private Long currencyId;//操作币种ID
- private String exchange;//交易所名称
- private Long apiMessageId;//交易所ID
- private Long memberId;//用户ID
- private String coinPair;//货币对
- private Integer coinType;//计价货币 1-USDTU本位 2-USDT币本位
- private Integer coinDirect;//方向 1-买多 2-买空
- private BigDecimal coinLevel;//杠杆倍数
- private BigDecimal pageNum;//张数
- private BigDecimal price;//均价
- private BigDecimal amount;//总价
- private BigDecimal profit;//盈亏
- private BigDecimal fee;//费用与返佣
- private BigDecimal singleOrder;//单序
- private BigDecimal quantity;//数量
- private Integer directStatus;//策略 1-顺势 2-逆势
- private Integer type;//方式 1.网络 2.其他
- private Integer status;//所属状态 1-开仓 2-平仓
- private Integer finishStatus;//所属状态 1-未完成 2-已完成 3-撤单 4-已卖出(针对买单由此状态)5.-交易失败
- private String ordId;//交易所订单ID
- private BigDecimal sellPrice;//计划平仓价格
- private BigDecimal incomePrice;//平仓传入价格
- private BigDecimal rangeRatio;//比率区域
- private Integer lockStatus;//卖出状态 0-未锁定 1-已锁定
- private String buyRediskey;//买单的rediskey
- private Integer tickSz;//下单精度
-
- @TableField(exist = false)
- private String startTime;//开始时间
- @TableField(exist = false)
- private String endTime;//结束时间
- @TableField(exist = false)
- private Integer excludeFinishStatus;//查询时排除状态
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/impl/OKXQueryOrderServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/impl/OKXQueryOrderServiceImpl.java
deleted file mode 100644
index 8913a48..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/impl/OKXQueryOrderServiceImpl.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.query.impl;
-
-import cn.hutool.core.util.ObjectUtil;
-import com.alibaba.fastjson.JSON;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsResponse;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OKXContants;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.vo.BalanceVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.query.IQueryOrderService;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.query.dto.QuantOperateRecode;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.query.vo.QuantCheckOrderVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.query.vo.QuantOperateRecodeVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.VerifyAccountFactory;
-import com.xcong.excoin.modules.okxNewPrice.zhanghu.IApiMessageService;
-import com.xcong.excoin.modules.okxNewPrice.zhanghu.ZhangHuEnum;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.json.JSONObject;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.math.BigDecimal;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.LinkedHashMap;
-
-@Service("oKXQueryOrderServiceImpl")
-@RequiredArgsConstructor
-@Slf4j
-public class OKXQueryOrderServiceImpl implements IQueryOrderService {
- @Value("spring.OKEX.baseurl")
- private String baseurl;
-
- private final IApiMessageService apiMessageService;
-
- private final VerifyAccountFactory verifyAccountFactory;
-
- private static String hmacSha256(String data, String key) throws Exception {
- Mac mac = Mac.getInstance("HmacSHA256");
- SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
- mac.init(secretKeySpec);
- return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes()));
- }
-
- @SneakyThrows
- @Override
- public FebsResponse QueryOrder(QuantApiMessage quantApiMessage, String instId, String clOrdId) {
- String url = baseurl + "/api/v5/trade/order?instId=" + instId + "&clOrdId=" + clOrdId; // 构建请求URL
- try {
- HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
- connection.setRequestMethod("GET");
- connection.setRequestProperty("Content-Type", "application/json");
- connection.setRequestProperty("OK-ACCESS-KEY", quantApiMessage.getASecretkey());
- connection.setRequestProperty("OK-ACCESS-SIGN", hmacSha256(quantApiMessage.getBSecretkey(), clOrdId)); // 根据需要生成签名
- connection.setRequestProperty("OK-ACCESS-TIMESTAMP", String.valueOf(System.currentTimeMillis() / 1000));
- connection.setRequestProperty("OK-ACCESS-PASSPHRASE", "your_passphrase"); // 替换为您的Passphrase
-
- int responseCode = connection.getResponseCode();
-
- if (responseCode == HttpURLConnection.HTTP_OK) {
- BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- String inputLine;
- StringBuilder response = new StringBuilder();
-
- while ((inputLine = in.readLine()) != null) {
- response.append(inputLine);
- }
- in.close();
-
- JSONObject jsonResponse = new JSONObject(response.toString());
- QuantCheckOrderVo quantCheckOrderVo = new QuantCheckOrderVo();
- if (jsonResponse.has("clOrdId") && StringUtils.isNotBlank(jsonResponse.getString("clOrdId"))) {
- quantCheckOrderVo.setTradeNumber(jsonResponse.getString("clOrdId"));
- }
- if (jsonResponse.has("ordId") && StringUtils.isNotBlank(jsonResponse.getString("ordId"))) {
- quantCheckOrderVo.setOrdId(jsonResponse.getString("ordId"));
- }
- if (jsonResponse.has("pnl") && StringUtils.isNotBlank(jsonResponse.getString("pnl"))) {
- quantCheckOrderVo.setProfit(new BigDecimal(jsonResponse.getString("pnl")));
- }
- if (jsonResponse.has("sz") && StringUtils.isNotBlank(jsonResponse.getString("sz"))) {
- quantCheckOrderVo.setPageNum(new Integer(jsonResponse.getString("sz")));
- }
- if (jsonResponse.has("fillPx") && StringUtils.isNotBlank(jsonResponse.getString("fillPx"))) {
- quantCheckOrderVo.setPrice(new BigDecimal(jsonResponse.getString("fillPx")));
- BigDecimal total = new BigDecimal(new Integer(jsonResponse.getString("sz"))).multiply(new BigDecimal(jsonResponse.getString("fillPx")));
- quantCheckOrderVo.setAmount(total);
- }
- return new FebsResponse().success().data(quantCheckOrderVo);
- } else {
- return new FebsResponse().fail().message("交易所订单查询异常");
- }
- } catch (Exception e) {
- return new FebsResponse().fail().message("订单查询异常");
- }
- }
-
- @Override
- public FebsResponse checkOrder(QuantOperateRecode operateRecode) {
- log.info("查询OKX订单信息:{}",operateRecode);
-
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("参数错误");
- }
-
- OKXAccount okxAccount = (OKXAccount) verifyAccountFactory.getAccountMap().get(quantApiMessage.getExchange())
- .initAccount(quantApiMessage);
- ArrayList<BalanceVo> balanceVos = new ArrayList<>();
-
- LinkedHashMap<String, Object> orderParameters = new LinkedHashMap<>();
- orderParameters.put("clOrdId", operateRecode.getTradeNumber());
- //将字符串BTC-USDTU-空 截取为 BTC-USDT
- String coinPair = operateRecode.getCoinPair().substring(0, operateRecode.getCoinPair().indexOf("-USDT")+5);
- orderParameters.put("instId", coinPair+"-SWAP");
- String orderStr = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.ORDER, orderParameters, HttpMethod.GET, okxAccount.isSimluate());
- log.info("查询OKX订单返回信息:{}",orderStr);
- QuantOperateRecodeVo quantOperateRecodeVo = new QuantOperateRecodeVo();
- com.alibaba.fastjson.JSONObject orderStrJson = JSON.parseObject(orderStr);
- String code = orderStrJson.getString("code");
- if("0".equals(code)){
- com.alibaba.fastjson.JSONObject data = orderStrJson.getJSONArray("data").getJSONObject(0);
- quantOperateRecodeVo.setQuantity(ObjectUtil.isEmpty(data.getString("accFillSz"))?new BigDecimal("0"): new BigDecimal(data.getString("accFillSz")));
- quantOperateRecodeVo.setPrice(ObjectUtil.isEmpty(data.getString("avgPx"))?new BigDecimal("0"): new BigDecimal(data.getString("avgPx")));
- quantOperateRecodeVo.setProfit(ObjectUtil.isEmpty(data.getString("pnl"))?new BigDecimal("0"): new BigDecimal(data.getString("pnl")));
- quantOperateRecodeVo.setFee(ObjectUtil.isEmpty(data.getString("fee"))?new BigDecimal("0"): new BigDecimal(data.getString("fee")));
- quantOperateRecodeVo.setExchangeNumber(data.getString("ordId"));
- quantOperateRecodeVo.setCoinLevel(ObjectUtil.isEmpty(data.getString("lever"))?new BigDecimal("0"): new BigDecimal(data.getString("lever")));
- quantOperateRecodeVo.setOrdType(data.getString("ordType"));
- quantOperateRecodeVo.setExChangeState(data.getString("state"));
- } else if("51603".equals(code)){
- quantOperateRecodeVo.setQuantity(new BigDecimal("0"));
- quantOperateRecodeVo.setPrice(new BigDecimal("0"));
- quantOperateRecodeVo.setProfit(new BigDecimal("0"));
- quantOperateRecodeVo.setCoinLevel(new BigDecimal("0"));
- quantOperateRecodeVo.setExchangeNumber("");
- quantOperateRecodeVo.setOrdType("");
- quantOperateRecodeVo.setExChangeState("canceled");
- } else {
- return null;
- }
-
- return new FebsResponse().success().data(quantOperateRecodeVo);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/vo/QuantCheckOrderVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/vo/QuantCheckOrderVo.java
deleted file mode 100644
index a462272..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/vo/QuantCheckOrderVo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.query.vo;
-
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * 订单返回信息
- */
-@Data
-public class QuantCheckOrderVo{
-
- private String tradeNumber;//交易编号
- private Integer pageNum;//张数
- private BigDecimal price;//均价
- private BigDecimal amount;//总价
- private BigDecimal profit;//盈亏
- private String ordId;//交易所订单ID
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/vo/QuantOperateRecodeVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/vo/QuantOperateRecodeVo.java
deleted file mode 100644
index df9d931..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/query/vo/QuantOperateRecodeVo.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.query.vo;
-
-
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * 合约操作记录
- */
-@Data
-public class QuantOperateRecodeVo{
-
- private String tradeNumber;//交易编号
- private Long apiMessageId;//交易所ID
- private String exchange;//交易所名称
- private String exchangeNumber;//交易所交易编号
- private String operationCode;//操作编号
- private Long currencyId;//操作币种ID
- private Long memberId;//用户ID
- private String coinPair;//货币对
- private Integer coinDirect;//方向 1-买多 2-买空
- private BigDecimal coinLevel;//杠杆倍数
- private BigDecimal pageNum;//张数
- private BigDecimal quantity;//数量
- private BigDecimal price;//均价
- private BigDecimal amount;//成交金额
- private BigDecimal profit;//盈亏
- private String sellTradeNumber;//卖出的订单号
- private BigDecimal fee;//费用与返佣
- private BigDecimal singleOrder;//单序
- private BigDecimal sellPrice;//计划平仓价格
- private Integer coinType;//计价货币 1-USDTU本位 2-USDT币本位
- private Integer directStatus;//策略 1-顺势 2-逆势
- private Integer type;//方式 1.网络 2.其他
- private Integer status;//所属状态 1-开仓 2-平仓
- private Integer tradeStatus;//交易状态 1-未完成 2-成功 3-失败
- private Integer finishStatus;//所属状态 1-未完成 2-已完成 3-撤单 4-已卖出(针对买单由此状态)5.-交易失败
- private String exChangeState;//交易所状态
- private Integer lockStatus;//卖出状态 0-未锁定 1-已锁定
- private Integer tickSz;//下单精度 1-0.1 2-0.01 3-0.001 4-0.0001 5-0.00001
- private String ordType;//订单类型 订单类型 market:市价单 limit:限价单 post_only:只做maker单 fok:全部成交或立即取消 ioc:立即成交并取消剩余 optimal_limit_ioc:市价委托立即成交并取消剩余(仅适用交割、永续)
- //mmp:做市商保护(仅适用于组合保证金账户模式下的期权订单) mmp_and_post_only:做市商保护且只做maker单(仅适用于组合保证金账户模式下的期权订单) op_fok:期权简选(全部成交或立即取消)
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeEventEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeEventEnum.java
deleted file mode 100644
index 17e05bf..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeEventEnum.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade;
-
-import lombok.Getter;
-
-@Getter
-public enum TradeEventEnum {
-
-
- TRADE_CLOSE_POSITION("CLOSE_POSITION",
- "编码:{},用户:{}, 触发价:{},实际成交价格:{},执行全平操作"),
-
- TRADE_SELL("SELL",
- "编码:{},用户:{}, 触发价:{},实际成交价格:{},执行平仓操作"),
-
- TRADE_BUY("BUY",
- "编码:{},用户:{}, 触发价:{},实际成交价格:{},执行开仓操作");
-
- private String eventPoint;
-
- private String eventDec;
-
-
- TradeEventEnum(String eventPoint, String eventDec) {
- this.eventPoint = eventPoint;
- this.eventDec = eventDec;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeEventRunner.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeEventRunner.java
deleted file mode 100644
index c14b24e..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeEventRunner.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade;
-
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.impl.TradeServiceBuy;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.impl.TradeServiceClosePosition;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.impl.TradeServiceSell;
-
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 交易事件运行类,用于根据不同的事件点选择相应的交易策略并执行
- */
-public class TradeEventRunner {
-
- // 使用线程安全的ConcurrentHashMap存储交易事件和对应的策略服务
- private static final Map<String, TradeService> TRADE_EVENT_MAP = new ConcurrentHashMap<>();
-
- static {
- // 初始化策略
- List<TradeService> tradeServices = Arrays.asList(
- new TradeServiceBuy(), // 买入策略
- new TradeServiceSell(), // 卖出策略
- new TradeServiceClosePosition() // 平仓策略
- );
-
- // 将策略放入ConcurrentHashMap中,确保线程安全
- for (TradeService service : tradeServices) {
- TRADE_EVENT_MAP.put(service.tradeEvent(), service);
- }
- }
-
- /**
- * 根据事件点选择并执行相应的交易策略
- *
- * @param eventPoint 事件点,用于匹配相应的交易策略
- * @param tradeRequest 包含交易请求信息的LinkedHashMap
- * @param okxAccount OKX账户信息,用于执行交易
- * @return 交易执行的结果
- * @throws FebsException 如果找不到对应的交易策略,则抛出异常
- */
- public static String runTradeEvent(String eventPoint, LinkedHashMap<String, Object> tradeRequest, OKXAccount okxAccount) {
- TradeService tradeService = TRADE_EVENT_MAP.get(eventPoint);
- if (tradeService == null) {
- throw new FebsException("交易EVENT异常");
- }
-
- return tradeService.doTrade(tradeRequest,okxAccount);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequest.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequest.java
deleted file mode 100644
index 3aec237..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade;
-
-import lombok.Data;
-
-@Data
-public class TradeRequest {
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequestBuy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequestBuy.java
deleted file mode 100644
index 5189e06..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequestBuy.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-@Data
-public class TradeRequestBuy implements Serializable {
- /**
- * 实现了 Serializable 接口,rabbitmq可以直接发送它,但需要确保 SimpleMessageConverter 能够处理它(对象简单,不是复杂的对象)
- */
- private static final long serialVersionUID = 1L;
-
- private Long strategiesId;//策略ID ReturnBuyVo.strategyId
-
- private String tradeCode;//自定义订单编号
-
- private Double tradeCnt;//交易数量 ReturnBuyVo.quantity
- /**
- * 限定价格
- * 限定价格为0的时候,表示市价操作当前订单
- */
- private String limitPrice = "0";
- /**
- * 产品ID,如 BTC-USDT
- */
- private String instId; //ReturnBuyVo.instId
- /**
- * 持仓方向
- * 在开平仓模式下必填,且仅可选择 long 或 short。 仅适用交割、永续。
- * 1-long 2-short
- */
- private Integer positionSide = 1;
- /**
- * 1 - isolated:逐仓 ;2 - cross:全仓
- * 交易模式
- * 保证金模式:isolated:逐仓 ;cross:全仓
- * 非保证金模式:cash:非保证金
- * spot_isolated:现货逐仓(仅适用于现货带单) ,现货带单时,tdMode 的值需要指定为spot_isolated
- */
- private Integer tdMode = 2;
-
- private BigDecimal priceRange; //买入的价格段位
-
- private Long operationCurrencyId; //操作货币id
-
- private String redisKey; //redisKey 用于标识是否已经处理过
-
- private String exchange; //交易所
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequestSell.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequestSell.java
deleted file mode 100644
index d167070..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeRequestSell.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.vo.SellOrderVo;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.List;
-
-@Data
-public class TradeRequestSell implements Serializable {
- /**
- * 实现了 Serializable 接口,rabbitmq可以直接发送它,但需要确保 SimpleMessageConverter 能够处理它(对象简单,不是复杂的对象)
- */
- private static final long serialVersionUID = 1L;
-
- private Long strategiesId;//策略ID ReturnVo.strategyId
-
- private String tradeCode;//自定义订单编号
-
- private BigDecimal rangeRatio;//区域比率
-
- private BigDecimal incomePrice;//平仓传入价格
-
- private Double tradeCnt;//交易数量 ReturnVo.quantity
- /**
- * 限定价格
- * 限定价格为0的时候,表示市价操作当前订单
- */
- private String limitPrice = "0";
- /**
- * 产品ID,如 BTC-USDT
- */
- private String instId; //ReturnVo.instId
- /**
- * 持仓方向
- * 在开平仓模式下必填,且仅可选择 long 或 short。 仅适用交割、永续。
- * 1-long 2-short
- */
- private Integer positionSide = 1;
- /**
- * 1 - isolated:逐仓 ;2 - cross:全仓
- * 交易模式
- * 保证金模式:isolated:逐仓 ;cross:全仓
- * 非保证金模式:cash:非保证金
- * spot_isolated:现货逐仓(仅适用于现货带单) ,现货带单时,tdMode 的值需要指定为spot_isolated
- */
- private Integer tdMode = 2;
-
- private List<SellOrderVo> sellOrderList; //卖出订单列表,当operations为buy时,该字段为空
-
- private Long operationCurrencyId; //操作货币id
-
- private String redisKey; //redisKey 用于标识是否已经处理过
-
- private String exchange; //交易所
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeService.java
deleted file mode 100644
index f19809a..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/TradeService.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-
-import java.util.LinkedHashMap;
-
-public interface TradeService {
- /**
- * 采用策略
- * @return
- */
- String tradeEvent();
-
- /**
- * 执行
- * @param tradeDto
- * @param okxAccount
- */
- String doTrade(LinkedHashMap<String, Object> tradeDto, OKXAccount okxAccount);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceBuy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceBuy.java
deleted file mode 100644
index b303fda..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceBuy.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade.impl;
-
-import com.alibaba.fastjson.JSON;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OKXContants;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.ParameterChecker;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeEventEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.LinkedHashMap;
-
-@Slf4j
-@RequiredArgsConstructor
-public class TradeServiceBuy implements TradeService {
-
- @Override
- public String tradeEvent() {
- return TradeEventEnum.TRADE_BUY.getEventPoint();
- }
-
- @Override
- public String doTrade(LinkedHashMap<String, Object> tradeDto, OKXAccount okxAccount) {
- ParameterChecker.checkParameter(tradeDto, "instId", String.class);
- ParameterChecker.checkParameter(tradeDto, "tdMode", String.class);
- ParameterChecker.checkParameter(tradeDto, "side", String.class);
- ParameterChecker.checkParameter(tradeDto, "ordType", String.class);
- ParameterChecker.checkParameter(tradeDto, "sz", Double.class);
- String placeOrderRspOkxRestResponse = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.ORDER, tradeDto, HttpMethod.POST, okxAccount.isSimluate());
- log.info("开仓响应:{}",JSON.parseObject(placeOrderRspOkxRestResponse).get("data"));
- /**
- * todo 下单之后的日志处理
- */
- return placeOrderRspOkxRestResponse;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceClosePosition.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceClosePosition.java
deleted file mode 100644
index c06bcdb..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceClosePosition.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade.impl;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeEventEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.LinkedHashMap;
-
-@Slf4j
-@RequiredArgsConstructor
-public class TradeServiceClosePosition implements TradeService {
- @Override
- public String tradeEvent() {
- return TradeEventEnum.TRADE_CLOSE_POSITION.getEventPoint();
- }
-
- @Override
- public String doTrade(LinkedHashMap<String, Object> tradeDto, OKXAccount okxAccount) {
- System.out.println(this.tradeEvent());
- return null;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceSell.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceSell.java
deleted file mode 100644
index 6a36a4c..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/impl/TradeServiceSell.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade.impl;
-
-import com.alibaba.fastjson.JSON;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OKXContants;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.ParameterChecker;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeEventEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.trade.TradeService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.LinkedHashMap;
-
-@Slf4j
-@RequiredArgsConstructor
-public class TradeServiceSell implements TradeService {
- @Override
- public String tradeEvent() {
- return TradeEventEnum.TRADE_SELL.getEventPoint();
- }
-
- @Override
- public String doTrade(LinkedHashMap<String, Object> tradeDto, OKXAccount okxAccount) {
- ParameterChecker.checkParameter(tradeDto, "instId", String.class);
- ParameterChecker.checkParameter(tradeDto, "tdMode", String.class);
- ParameterChecker.checkParameter(tradeDto, "side", String.class);
- ParameterChecker.checkParameter(tradeDto, "ordType", String.class);
- ParameterChecker.checkParameter(tradeDto, "sz", Double.class);
- String placeOrderRspOkxRestResponse = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.ORDER, tradeDto, HttpMethod.POST, okxAccount.isSimluate());
- log.info("平仓响应:{}", JSON.parseObject(placeOrderRspOkxRestResponse).get("data"));
- /**
- * todo 下单之后的日志处理
- */
-
- return placeOrderRspOkxRestResponse;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/vo/SellOrderVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/vo/SellOrderVo.java
deleted file mode 100644
index 2d14a67..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/trade/vo/SellOrderVo.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.trade.vo;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2021-09-16
- **/
-@Data
-public class SellOrderVo implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- private String ordId; //交易所订单号
-
- private String tradeNumber; //本地订单号
-
- private BigDecimal quantity;//数量
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/IVerifyAccountService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/IVerifyAccountService.java
deleted file mode 100644
index fdb0269..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/IVerifyAccountService.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsResponse;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Account;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto.*;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo.ApiAccountHoldVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo.ApiPositionsInfoVo;
-
-//检查账户信息是否合格 欧易调用的接口是交易账户/REST API/查看账户余额
-public interface IVerifyAccountService {
-
- /**
- * 初始化api信息
- * @return
- */
- OKXAccount initAccount(QuantApiMessage quantApiMessage);
- /**
- * 初始化api信息
- * @param apiKey
- * @param secretKey
- * @param accountType
- * @return
- */
- Account initAccountV2(String apiKey, String secretKey, String passPhrass, boolean accountType);
-
- FebsResponse verifyAccount(ApiMessageDto apiMessageDto);
-
- /**
- * 获取产品信息
- * @param apiValidApiMessageDto
- */
- FebsResponse getProductMess(ApiValidApiMessageDto apiValidApiMessageDto);
-
- /**
- * 获取当前价格
- * @param operateCurrencyDto
- */
- FebsResponse getCurrenPrice(OperateCurrencyDto operateCurrencyDto);
-
- /**
- * 获取杠杆列表
- * @param operateCurrencyLeverDto
- */
- FebsResponse getlever(OperateCurrencyLeverDto operateCurrencyLeverDto);
-
- /**
- * 设置币种杠杆
- * @param operateCurrencyLeverDto
- */
- FebsResponse setLever(OperateCurrencyLeverDto operateCurrencyLeverDto);
-
- /**
- * 获取持仓信息
- * @param quantApiMessage
- */
- FebsResponse testApiLink(QuantApiMessage quantApiMessage);
-
- /**
- * 获取账户总权益
- * @param apiAccountBalanceDto
- */
- void getAccountBalance(ApiAccountBalanceDto apiAccountBalanceDto);
-
- /**
- * 获取持仓概况
- * @param apiAccountBalanceInfoDto
- */
- ApiAccountHoldVo getAccountBalanceInfo(ApiAccountBalanceInfoDto apiAccountBalanceInfoDto);
-
- ApiPositionsInfoVo getAccountPositionsInfo(ApiPositionsInfoDto apiPositionsInfoDto);
-
- /**
- * 获取交易大数据
- * @return
- */
- FebsResponse getTradeData(ApiValidApiMessageDto apiValidApiMessageDto);
-
- /**
- * 获取买入卖出情况
- * @return
- */
- FebsResponse getBuySellSituation(ApiValidApiMessageDto apiValidApiMessageDto);
-
- /**
- * 获取持仓人数比
- * @return
- */
- FebsResponse getPositionRatio(ApiValidApiMessageDto apiValidApiMessageDto);
-
- /**
- * 获取合约持仓量及交易量
- * @return
- */
- FebsResponse getPositionTradingvolume(ApiValidApiMessageDto apiValidApiMessageDto);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/VerifyAccountFactory.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/VerifyAccountFactory.java
deleted file mode 100644
index 1ae8b06..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/VerifyAccountFactory.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify;
-
-import lombok.Data;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Component;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 账号验证工厂类
- * 该类用于管理不同交易所的账号验证服务通过传入的键获取相应的验证服务
- */
-@Component
-@Data
-public class VerifyAccountFactory {
-
- /**
- * OKX交易所的账号验证服务
- */
- @Qualifier("oKXVerifyAccount")
- private final IVerifyAccountService oKXVerifyAccount;
-
- /**
- * 存储不同交易所的账号验证服务的映射
- */
- private Map<String, IVerifyAccountService> accountMap = new HashMap<>();
-
- /**
- * 构造方法,初始化账号验证工厂
- * @param oKXVerifyAccount OKX交易所的账号验证服务
- */
- public VerifyAccountFactory(IVerifyAccountService oKXVerifyAccount) {
- this.oKXVerifyAccount = oKXVerifyAccount;
- accountMap.put("OKX", oKXVerifyAccount);
- }
-
- /**
- * 根据传入的键获取相应的账号验证服务
- * @param key 交易所的键,如"OKX"或"BINANCE"
- * @return 对应的账号验证服务
- */
- public IVerifyAccountService get(String key) {
- return accountMap.get(key);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalDto.java
deleted file mode 100644
index 00c9cc3..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalDto.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-
-@Data
-@ApiModel(value = "ApiAccountBalDto", description = "参数接收类")
-public class ApiAccountBalDto {
-
- @NotBlank(message = "请选择时间范围")
- @ApiModelProperty(value = "开始时间", example = "")
- private String startTime;//开始时间
-
- @NotBlank(message = "请选择时间范围")
- @ApiModelProperty(value = "结束时间", example = "")
- private String endTime;//结束时间
-
- @ApiModelProperty(value = "交易所类型", example = "1")
- private String exchange;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalanceDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalanceDto.java
deleted file mode 100644
index 9c5dc63..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalanceDto.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-
-@Data
-@ApiModel(value = "ApiAccountBalanceDto", description = "参数接收类")
-public class ApiAccountBalanceDto {
-
- @ApiModelProperty(value = "apiMessageId", example = "11")
- private Long id;
-
- @NotNull(message = "账户类型不能为空")
- @ApiModelProperty(value = "账户类型:实盘账户-true, 模拟账户-false", example = "false")
- private boolean accountType;
-
- @ApiModelProperty(value = "币种名称", example = "BTC")
- private String coinName;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalanceInfoDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalanceInfoDto.java
deleted file mode 100644
index 7774264..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountBalanceInfoDto.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "ApiAccountBalanceInfoDto", description = "参数接收类")
-public class ApiAccountBalanceInfoDto {
-
- @ApiModelProperty(value = "apiMessageId", example = "11")
- private Long id;
-
- @ApiModelProperty(value = "币种名称", example = "BTC")
- private String coinName;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountProfitDailyDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountProfitDailyDto.java
deleted file mode 100644
index 229f292..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiAccountProfitDailyDto.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "ApiAccountBalanceInfoDto", description = "参数接收类")
-public class ApiAccountProfitDailyDto {
-
- @ApiModelProperty(value = "交易所类型", example = "1")
- private String exchange;
-
- @ApiModelProperty(value = "开始时间", example = "")
- private String startTime;//开始时间
-
- @ApiModelProperty(hidden = true)
- private String endTime;//结束时间
-
- @ApiModelProperty(hidden = true)
- private Long memberId;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiMessageDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiMessageDto.java
deleted file mode 100644
index 2b9f2f2..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiMessageDto.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-
-/**
- * @author lyq
- * @date 2024-09-16
- **/
-@Data
-public class ApiMessageDto {
-
- @ApiModelProperty(value = "id")
- private Long id;
-
- @ApiModelProperty(value = "会员id", example = "11")
- private Long memberId;
-
- @NotBlank(message = "交易所不能为空")
- @ApiModelProperty(value = "交易所", example = "jys")
- private String exchange;
-
- @NotBlank(message = "a秘钥不能为空")
- @ApiModelProperty(value = "a秘钥", example = "123456")
- private String aSecretkey;
-
- @NotBlank(message = "b秘钥不能为空")
- @ApiModelProperty(value = "b秘钥", example = "123456")
- private String bSecretkey;
-
- @NotBlank(message = "passPhrass不能为空")
- @ApiModelProperty(value = "passPhrass", example = "123456")
- private String passPhrass;
-
- @NotNull(message = "账户类型不能为空")
- @ApiModelProperty(value = "账户类型:实盘账户-true, 模拟账户-false", example = "false")
- private String accountType;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiPositionsInfoDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiPositionsInfoDto.java
deleted file mode 100644
index 3222f37..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiPositionsInfoDto.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-@Data
-@ApiModel(value = "ApiAccountBalanceInfoDto", description = "参数接收类")
-public class ApiPositionsInfoDto {
-
- @ApiModelProperty(value = "apiMessageId", example = "11")
- private Long id;
-
- @ApiModelProperty(value = "币种名称", example = "BTC")
- private String coinName;
-
- @ApiModelProperty(value = "交易所名称", example = "OKX")
- private String exchange;
-
- @ApiModelProperty(value = "持仓ID", example = "")
- private String posId;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiValidApiMessageDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiValidApiMessageDto.java
deleted file mode 100644
index 3a57022..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/ApiValidApiMessageDto.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-
-@Data
-@ApiModel(value = "ApiValidApiMessageDto", description = "API信息参数接收类")
-public class ApiValidApiMessageDto {
-
- @NotNull(message = "apiMessageId")
- @ApiModelProperty(value = "apiMessageId", example = "11")
- private Long id;
-
- @NotNull(message = "账户类型不能为空")
- @ApiModelProperty(value = "账户类型:实盘账户-true, 模拟账户-false", example = "false")
- private boolean accountType;
-
- @ApiModelProperty(value = "币种名称", example = "BTC")
- private String coinName;
-
- @ApiModelProperty(value = "交易所", example = "OKX")
- private String exchange;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/OperateCurrencyDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/OperateCurrencyDto.java
deleted file mode 100644
index 4aac95a..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/OperateCurrencyDto.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * @author wzy
- * @date 2024-08-10
- **/
-@Data
-@ApiModel(value = "OperateCurrencyDto", description = "登录接口参数接收类")
-public class OperateCurrencyDto {
-
- @ApiModelProperty(value = "id")
- private Long id;
-
- @ApiModelProperty(value = "交易所ID", example = "")
- private Long apiMessageId;//交易所ID
-
- @ApiModelProperty(value = "交易所名称", example = "")
- private String exchange;//交易所名称
-
-// @NotBlank(message = "币种标识不能为空")
-// @ApiModelProperty(value = "币种标识", example = "DOGE")
-// private String coinSymbol;//货币对(交易货币(币种标识))
-
- @NotBlank(message = "币种标识不能为空")
- @ApiModelProperty(value = "币种标识", example = "DOGE")
- private String coinName;//货币货币名称(交易货币(币种标识))
-
- @NotBlank(message = "计价货币不能为空")
- @ApiModelProperty(value = "计价货币", example = "USDTU")
- private Integer coinType;//计价货币 1-USDTU本位 2-USDT币本位
-
- @NotBlank(message = "方向不能为空")
- @ApiModelProperty(value = "方向", example = "1")
- private Integer coinDirect;//方向 1-多 2-空
-
- @ApiModelProperty(value = "策略方向", example = "1")
- private Integer directStatus;//策略方向 1-顺势 2-逆势
-
- @ApiModelProperty(value = "货币对", example = "-SWAP")
- private String coinSymbol;//货币对(交易货币(币种标识))
-
- @ApiModelProperty(value = "用户id", example = "1")
- private Long MemberId;//用户ID
-
- @ApiModelProperty(value = "账户类型BTC-USD:实盘账户-true, 模拟账户-false", example = "false")
- private boolean accountType;
-
- @ApiModelProperty(value = "是否开启监控 0-否 1-是", example = "0")
- private Integer monitorStatus;//是否开启监控 0-未开启 1-已开启
-
- @ApiModelProperty(value = "杠杆倍率", example = "20")
- private String lever;//杠杆倍率
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/OperateCurrencyLeverDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/OperateCurrencyLeverDto.java
deleted file mode 100644
index 3c42ab9..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/OperateCurrencyLeverDto.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * @author wzy
- * @date 2024-08-10
- **/
-@Data
-@ApiModel(value = "OperateCurrencyLeverDto", description = "倍率查询接收类")
-public class OperateCurrencyLeverDto {
-
- @ApiModelProperty(value = "apiMessageId", example = "1")
- private Long apiMessageId;//交易所ID
-
- @ApiModelProperty(value = "产品ID", example = "BTC-USDT")
- private String instId;//交易所名称
-
- @ApiModelProperty(value = "杠杆倍率", example = "20")
- private String lever;//杠杆倍率
-
- @ApiModelProperty(value = "交易所名称", example = "OKX")
- private String exchange;//交易所名称
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/TradeBigdataDto.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/TradeBigdataDto.java
deleted file mode 100644
index bb16168..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/dto/TradeBigdataDto.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.io.Serializable;
-
-@Data
-@ApiModel(value = "TradeBigdataDto", description = "交易大数据数据接收类")
-public class TradeBigdataDto implements Serializable {
- private static final long serialVersionUID = 1L;
- @ApiModelProperty(value = "数据产生时间", example = "2024-09-18 14:38:01")
- private String ts;//数据产生时间
-
- @ApiModelProperty(value = "卖出量", example = "1000")
- private String sellVol;//卖出量
-
- @ApiModelProperty(value = "买入量", example = "1000")
- private String buyVol;//买入量
-
- @ApiModelProperty(value = "多空人数比", example = "0.8")
- private String longShortAcctRatio;//多空人数比
-
- @ApiModelProperty(value = "持仓总量", example = "1000")
- private String oi;//持仓总量
-
- @ApiModelProperty(value = "交易总量", example = "1000")
- private String vol;//交易总量
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/enums/PublicStatusEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/enums/PublicStatusEnum.java
deleted file mode 100644
index a267e11..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/enums/PublicStatusEnum.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.enums;
-
-import java.math.BigDecimal;
-
-public class PublicStatusEnum {
-
- /**
- * API验证返回状态
- */
- public static final int API_MESSAGE_STATUS_SUCCESS = 1;
- public static final int API_MESSAGE_STATUS_FAIL = 0;
-
- /**
- * 货币对监控状态
- */
- //货币对监控状态开启
- public static final int CURRENCY_MONITOR_OPEN = 1;
-
- //货币对监控状态开启
- public static final int CURRENCY_ONLYSELL_OPEN = 1;
- //货币对监控状态关闭
-
- public static final int CURRENCY_MONITOR_CLOSE = 0;
- //是否开启过监听
- public static final int CURRENCY_MONITORED_OPEN = 1;
- //订单未完成
- public static final int ORDER_FINISH_STATUS_NO = 1;
- //订单已完成
- public static final int ORDER_FINISH_STATUS_YES = 2;
- //订单取消
- public static final int ORDER_FINISH_STATUS_CANEL = 3;
- //订单已卖出(针对买单)
- public static final int ORDER_FINISH_STATUS_SELL = 4;
- //订单下单失败
- public static final int ORDER_FINISH_STATUS_FAIL = 5;
-
- //其他方式卖出
- public static final int ORDER_FINISH_STATUS_OTHERSELL = 6;
-
- //买单
- public static final int ORDER_STATUS_BUY = 1;
-
- public static final BigDecimal ORDER_DOWN_RATIO= new BigDecimal("0.01");
- //买单
-
- public static final int ORDER_STATUS_SELL = 2;
-
-// public static final boolean AccountType = false;
-
- public static final int ORDER_FINISH_STATUS = 2;
-
- //订单卖出未锁定
- public static final int ORDER_SELL_LOCK_STATUS_NO = 0;
- //订单卖出已锁定
- public static final int ORDER_SELL_LOCK_STATUS_YES = 1;
-
- //定义超过开仓均价时需向下调整卖价的比率
- public static final BigDecimal HIGH_SELL_RATIO= new BigDecimal("1.1");
-
- //定义需要调整后的比率
- public static final BigDecimal HIGH_ADJUST_RATIO= new BigDecimal("1.03");
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/impl/OKXVerifyAccountServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/impl/OKXVerifyAccountServiceImpl.java
deleted file mode 100644
index fe5de75..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/impl/OKXVerifyAccountServiceImpl.java
+++ /dev/null
@@ -1,680 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.impl;
-
-import cn.hutool.core.util.ObjectUtil;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsException;
-import com.xcong.excoin.modules.okxNewPrice.utils.FebsResponse;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.DataUtil;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.OKXAccount;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.DefaultUrls;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.enums.HttpMethod;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.utils.OKXContants;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.IVerifyAccountService;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.dto.*;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.enums.PublicStatusEnum;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo.ApiAccountHoldVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo.ApiPositionsInfoVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo.ProductMessVo;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo.SinglemarketVo;
-import com.xcong.excoin.modules.okxNewPrice.zhanghu.IApiMessageService;
-import com.xcong.excoin.modules.okxNewPrice.zhanghu.ZhangHuEnum;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.math.BigDecimal;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.*;
-
-@Slf4j
-@Service("oKXVerifyAccount")
-@RequiredArgsConstructor
-public class OKXVerifyAccountServiceImpl implements IVerifyAccountService {
-
- private final IApiMessageService apiMessageService;
- @Value("${spring.OKEX.baseurl}")
- private String baseurl;
-
- @Override
- public OKXAccount initAccount(QuantApiMessage quantApiMessage) {
- return new OKXAccount(
- quantApiMessage.getAccountType().equalsIgnoreCase("true") ? DefaultUrls.USDM_PROD_URL : DefaultUrls.USDM_UAT_URL,
- quantApiMessage.getASecretkey(),
- quantApiMessage.getBSecretkey(),
- quantApiMessage.getPassPhrass(),
- !quantApiMessage.getAccountType().equalsIgnoreCase("true"));
-
- }
-
- @Override
- public OKXAccount initAccountV2(String apiKey, String secretKey, String passPhrass, boolean accountType) {
- return new OKXAccount(
- accountType ? DefaultUrls.USDM_PROD_URL : DefaultUrls.USDM_UAT_URL,
- apiKey,
- secretKey,
- passPhrass,
- !accountType);
- }
-
- @SneakyThrows
- @Override
- public FebsResponse verifyAccount(ApiMessageDto apiMessageDto) {
- if(validateAccount(apiMessageDto)){
- return new FebsResponse().success();
- }
- return new FebsResponse().fail();
- }
-
- @Override
- public FebsResponse getProductMess(ApiValidApiMessageDto apiValidApiMessageDto) {
- Long id = apiValidApiMessageDto.getId();
-
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("参数错误");
- }
-
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
- LinkedHashMap<String, Object> balanceParameters = new LinkedHashMap<>();
- balanceParameters.put("instType", "SWAP");
- if(StringUtils.isNotBlank(apiValidApiMessageDto.getCoinName())){
- balanceParameters.put("instId", apiValidApiMessageDto.getCoinName()+"-USD-SWAP");
- balanceParameters.put("instFamily", apiValidApiMessageDto.getCoinName()+"-USD");
- }
-
- String productStr = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.INSTRUMENTS, balanceParameters, HttpMethod.GET, okxAccount.isSimluate());
- log.info("productStr:{}", productStr);
- JSONObject balanceJson = JSON.parseObject(productStr);
- JSONObject data = balanceJson.getJSONArray("data").getJSONObject(0);
-
- ProductMessVo productMessVo = new ProductMessVo();
- productMessVo.setLotSz(data.getString("lotSz"));
- productMessVo.setMinSz(data.getString("minSz"));
- productMessVo.setTickSz(data.getString("tickSz"));
- productMessVo.setCtVal(data.getString("ctVal"));
-
- return new FebsResponse().success().data(productMessVo);
- }
-
- @Override
- public FebsResponse getCurrenPrice(OperateCurrencyDto operateCurrencyDto) {
-
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- if(null == quantApiMessage){
- return new FebsResponse().fail().message("请先配置交易所");
- }
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- LinkedHashMap<String, Object> balanceParameters = new LinkedHashMap<>();
- if(StringUtils.isNotBlank(operateCurrencyDto.getCoinSymbol())){
- balanceParameters.put("instId", operateCurrencyDto.getCoinSymbol()+"-SWAP");
- }
- String ticker = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.TICKER, balanceParameters, HttpMethod.GET, okxAccount.isSimluate());
-
- log.info("ticker================:{}", ticker);
-
- JSONObject jsonObject = JSON.parseObject(ticker);
- JSONObject data = jsonObject.getJSONArray("data").getJSONObject(0);
-
- SinglemarketVo singlemarketVo = new SinglemarketVo();
- singlemarketVo.setInstId(data.getString("instId"));
- singlemarketVo.setLast(data.getString("last"));
- singlemarketVo.setInstType(data.getString("instType"));
-
- return new FebsResponse().success().data(singlemarketVo);
- }
-
- @Override
- public FebsResponse getlever(OperateCurrencyLeverDto operateCurrencyLeverDto) {
-
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("参数错误");
- }
-
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
- LinkedHashMap<String, Object> balanceParameters = new LinkedHashMap<>();
- balanceParameters.put("instId", operateCurrencyLeverDto.getInstId());
- balanceParameters.put("mgnMode", "cross");
- String leverStr = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.LEVERAGE, balanceParameters, HttpMethod.GET, okxAccount.isSimluate());
- log.info("leverStr:{}", leverStr);
- JSONObject leverStrJson = JSON.parseObject(leverStr);
-
- Set<String> leverage = new HashSet<>();
-
- JSONArray details = leverStrJson.getJSONArray("data");
- int size = details.size();
- for (int i = 0; i < size; i++) {
- leverage.add(details.getJSONObject(i).getString("lever"));
- }
-
-
- log.info("leverage:{}", leverage);
-
- return new FebsResponse().success().data(leverage);
- }
-
- @Override
- public FebsResponse setLever(OperateCurrencyLeverDto operateCurrencyLeverDto) {
-
- log.info("OKX_SET_LEVEL");
- log.info("operateCurrencyLeverDto:{}", operateCurrencyLeverDto);
-
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("参数错误");
- }
-
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
- LinkedHashMap<String, Object> balanceParameters = new LinkedHashMap<>();
- balanceParameters.put("instId", operateCurrencyLeverDto.getInstId()+"-SWAP");
- balanceParameters.put("mgnMode", "cross");
- balanceParameters.put("lever", operateCurrencyLeverDto.getLever());
- String setleverStr = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.SETLEVERAGE, balanceParameters, HttpMethod.POST, okxAccount.isSimluate());
- log.info("setleverStr:{}", setleverStr);
- JSONObject leverStrJson = JSON.parseObject(setleverStr);
-
- String code = leverStrJson.getString("code");
- if("0".equals(code)||"59000".equals(code)){
- if("59000".equals(code)){
- return new FebsResponse().success().message("59000");
- }
- return new FebsResponse().success().message("设置杠杆成功");
- } else {
- return new FebsResponse().fail().message("设置杠杆失败");
- }
-
- }
-
- /**
- * 测试API链接
- *
- * @param quantApiMessage 包含API链接信息的DTO对象
- * @return 返回一个FebsResponse对象,包含验证结果和消息
- */
- @Override
- public FebsResponse testApiLink(QuantApiMessage quantApiMessage) {
- log.info("apiMessageDto:{}",quantApiMessage);
- try{
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 创建用于存储余额查询参数的容器
- LinkedHashMap<String, Object> balanceParameters = new LinkedHashMap<>();
- log.info("okxAccount:{}",okxAccount);
-
- // 发送签名请求以获取账户余额
- String balance = okxAccount.requestHandler.sendSignedRequest(okxAccount.baseUrl, OKXContants.BALANCE, balanceParameters, HttpMethod.GET, okxAccount.isSimluate());
- log.info("balance:{}",balance);
-
- // 解析余额响应JSON
- JSONObject balanceJson = JSON.parseObject(balance);
-
- // 检查余额响应代码,如果为0则表示成功
- if("0".equals(balanceJson.getString("code").toString())){
- // 更新QuantApiMessage状态为成功
- HashMap<String, Integer> objectObjectHashMap = new HashMap<>();
- objectObjectHashMap.put("state", PublicStatusEnum.API_MESSAGE_STATUS_SUCCESS);
- return new FebsResponse().success().data(objectObjectHashMap).message("账号验证成功");
- }
-
- // 返回验证失败的消息
- return new FebsResponse().fail().message("账号验证失败");
- } catch (Exception e){
- // 异常情况下返回验证失败的消息
- return new FebsResponse().fail().message("账号验证失败");
- }
- }
-
- /**
- * 获取账户余额的方法
- *
- * @param apiAccountBalanceDto 包含账户余额查询信息的数据传输对象
- * @throws FebsException 当API消息信息未设置时抛出异常
- */
- @Override
- public void getAccountBalance(ApiAccountBalanceDto apiAccountBalanceDto) {
- // 提取API消息ID、账户类型和币种名称
- String coinName = apiAccountBalanceDto.getCoinName();
-
- // 根据ID查询API消息信息
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(ZhangHuEnum.JIAOYISUO.getValue());
- // 检查API消息信息是否存在
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("API_MESSAGE信息未设置");
- }
-
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 构建查询余额的参数
- LinkedHashMap<String, Object> balanceParameters = new LinkedHashMap<>();
- balanceParameters.put("ccy", coinName);
- // 发送签名请求获取余额信息
- String balance = okxAccount.requestHandler.sendSignedRequest(
- okxAccount.baseUrl,
- OKXContants.BALANCE,
- balanceParameters,
- HttpMethod.GET,
- okxAccount.isSimluate());
- // 记录余额信息日志
- log.info("ACCOUNT_BALANCE:{}", balance);
- JSONObject balanceJson = JSON.parseObject(balance);
- JSONObject data = balanceJson.getJSONArray("data").getJSONObject(0);
- JSONArray details = data.getJSONArray("details");
- for (int i = 0; i < details.size(); i++) {
- JSONObject jsonObject = details.getJSONObject(i);
- // 总权益
- String bal = jsonObject.getString("eq");
-// String upl = jsonObject.getString("upl");
- }
- }
-
- @Override
- public ApiAccountHoldVo getAccountBalanceInfo(ApiAccountBalanceInfoDto apiAccountBalanceInfoDto) {
- ApiAccountHoldVo apiAccountHoldVo = new ApiAccountHoldVo();
-
- // 提取API消息ID、账户类型和币种名称
- Long apiMessageId = apiAccountBalanceInfoDto.getId();
- String coinName = apiAccountBalanceInfoDto.getCoinName();
-
- // 根据ID查询API消息信息
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(
- ZhangHuEnum.JIAOYISUO.getValue()
- );
- // 检查API消息信息是否存在
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("API_MESSAGE信息未设置");
- }
-
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 构建查询余额的参数
- LinkedHashMap<String, Object> balanceParameters = new LinkedHashMap<>();
- balanceParameters.put("ccy", coinName);
- // 发送签名请求获取余额信息
- String balance = okxAccount.requestHandler.sendSignedRequest(
- okxAccount.baseUrl,
- OKXContants.BALANCE,
- balanceParameters,
- HttpMethod.GET,
- okxAccount.isSimluate());
- // 记录余额信息日志
- log.info("ACCOUNT_BALANCE:{}", balance);
- JSONObject balanceJson = JSON.parseObject(balance);
- JSONObject data = balanceJson.getJSONArray("data").getJSONObject(0);
- JSONArray details = data.getJSONArray("details");
- for (int i = 0; i < details.size(); i++) {
- JSONObject jsonObject = details.getJSONObject(i);
- log.info("OKX-HOLD:",jsonObject);
- // 总权益
- String bal = jsonObject.getString("eq");//币种总权益
- String cashBal = jsonObject.getString("cashBal");//币种余额
- String availEq = jsonObject.getString("availEq");//可用保证金
- String availBal = jsonObject.getString("availBal");//可用余额
- String frozenBal = jsonObject.getString("frozenBal");//币种占用金额
- String imr = jsonObject.getString("imr");//币种维度全仓占用保证金,适用于现货和合约模式且有全仓仓位时
- String mgnRatio = jsonObject.getString("mgnRatio");//币种全仓保证金率,衡量账户内某项资产风险的指标
- String mmr = jsonObject.getString("mmr");//币种维度全仓维持保证金
- String upl = jsonObject.getString("upl");//未实现盈亏
- apiAccountHoldVo.setTotalBalance(new BigDecimal(bal));
- apiAccountHoldVo.setTotalPercent(new BigDecimal(upl));
- apiAccountHoldVo.setAvailableBalance(new BigDecimal(availBal));
-// apiAccountHoldVo.setHoldBalance(new BigDecimal(mmr));
- apiAccountHoldVo.setHoldBalance(new BigDecimal(mmr));
- apiAccountHoldVo.setUseBalance(new BigDecimal(mmr));
- apiAccountHoldVo.setCashBal(new BigDecimal(cashBal));
- apiAccountHoldVo.setFrozenBal(new BigDecimal(frozenBal));
- apiAccountHoldVo.setAvailEq(new BigDecimal(availEq));
- apiAccountHoldVo.setMgnRatio(mgnRatio);
- }
- return apiAccountHoldVo;
- }
-
- @Override
- public ApiPositionsInfoVo getAccountPositionsInfo(ApiPositionsInfoDto apiPositionsInfoDto) {
-
- log.info("getAccountPositionsInfo:{}",apiPositionsInfoDto);
- ApiPositionsInfoVo apiPositionsInfoVo = new ApiPositionsInfoVo();
- // 提取API消息ID、账户类型和币种名称
- Long apiMessageId = apiPositionsInfoDto.getId();
- String coinName = apiPositionsInfoDto.getCoinName();
-
- // 根据ID查询API消息信息
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(
- ZhangHuEnum.JIAOYISUO.getValue()
- );
- // 检查API消息信息是否存在
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("API_MESSAGE信息未设置");
- }
-
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 构建查询余额的参数
- LinkedHashMap<String, Object> positionsParameters = new LinkedHashMap<>();
- positionsParameters.put("instType", "SWAP");
- positionsParameters.put("instId", coinName+"-USDT-SWAP");
- try{
- // 发送签名请求获取余额信息
- String positions = okxAccount.requestHandler.sendSignedRequest(
- okxAccount.baseUrl,
- OKXContants.POSITIONS,
- positionsParameters,
- HttpMethod.GET,
- okxAccount.isSimluate());
- // 记录余额信息日志
- log.info("POSITIONS:{}", positions);
- JSONObject balanceJson = JSON.parseObject(positions);
- String code = balanceJson.getString("code");
- if(!"0".equals(code)){
- return null;
- }
- JSONObject data = balanceJson.getJSONArray("data").getJSONObject(0);
- String avgPx = data.getString("avgPx");
- String upl = data.getString("upl");
- String markPx = data.getString("markPx");
- String bePx = data.getString("bePx");
- String pos = data.getString("pos");
- apiPositionsInfoVo.setUpl(new BigDecimal(ObjectUtil.isNotEmpty(upl)? DataUtil.getDecimalDigits8(upl):"0"));
- apiPositionsInfoVo.setAvgPx(new BigDecimal(ObjectUtil.isNotEmpty(avgPx)?DataUtil.getDecimalDigits8(avgPx):"0"));
- apiPositionsInfoVo.setMarkPx(new BigDecimal(ObjectUtil.isNotEmpty(markPx)?DataUtil.getDecimalDigits8(markPx):"0"));
- apiPositionsInfoVo.setBePx(new BigDecimal(ObjectUtil.isNotEmpty(bePx)?DataUtil.getDecimalDigits8(bePx):"0"));
- apiPositionsInfoVo.setPos(new BigDecimal(ObjectUtil.isNotEmpty(pos)?DataUtil.getDecimalDigits8(pos):"0"));
- apiPositionsInfoVo.setCoinName(coinName);
- return apiPositionsInfoVo;
- }catch (Exception e){
- return null;
- }
-
- }
-
- @Override
- public FebsResponse getTradeData(ApiValidApiMessageDto apiValidApiMessageDto) {
-
- log.info("getTradeData:{}", apiValidApiMessageDto);
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(
- ZhangHuEnum.JIAOYISUO.getValue()
- );
- // 检查API消息信息是否存在
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("API_MESSAGE信息未设置");
- }
-
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 构建查询余额的参数
- LinkedHashMap<String, Object> positionsParameters = new LinkedHashMap<>();
- try{
- // 发送签名请求获取余额信息
- String tradedata = okxAccount.requestHandler.sendSignedRequest(
- okxAccount.baseUrl,
- OKXContants.TRADEDATA,
- positionsParameters,
- HttpMethod.GET,
- okxAccount.isSimluate());
- // 记录余额信息日志
- log.info("tradedata:{}", tradedata);
- JSONObject balanceJson = JSON.parseObject(tradedata);
- String code = balanceJson.getString("code");
- if(!"0".equals(code)){
- return null;
- }
- JSONObject dataObject = balanceJson.getJSONObject("data");
- JSONArray contractArray = dataObject.getJSONArray("contract");
- List<String> contractList = new ArrayList<>();
- if (contractArray != null) {
- for (int i = 0; i < contractArray.size(); i++) {
- contractList.add(contractArray.getString(i));
- }
- }
- return new FebsResponse().data(contractList);
- }catch (Exception e){
- return null;
- }
- }
-
- @Override
- public FebsResponse getBuySellSituation(ApiValidApiMessageDto apiValidApiMessageDto) {
- log.info("getBuySellSituation:{}", apiValidApiMessageDto);
-
- String coinName = apiValidApiMessageDto.getCoinName();// String coinName = "BTC";
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(
- ZhangHuEnum.JIAOYISUO.getValue()
- );
- // 检查API消息信息是否存在
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("API_MESSAGE信息未设置");
- }
-
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 构建查询余额的参数
- LinkedHashMap<String, Object> positionsParameters = new LinkedHashMap<>();
- positionsParameters.put("period", "4H");
- positionsParameters.put("instId", coinName+"-USDT-SWAP");
- positionsParameters.put("limit", "1");
- try{
- // 发送签名请求获取余额信息
- String buySellSituation = okxAccount.requestHandler.sendSignedRequest(
- okxAccount.baseUrl,
- OKXContants.BUYSELLSITUATION,
- positionsParameters,
- HttpMethod.GET,
- okxAccount.isSimluate());
- // 记录余额信息日志
- log.info("buySellSituation:{}", buySellSituation);
- JSONObject balanceJson = JSON.parseObject(buySellSituation);
- String code = balanceJson.getString("code");
- if(!"0".equals(code)){
- return null;
- }
- JSONArray dataArray = balanceJson.getJSONArray("data");
- TradeBigdataDto tradeBigdataDto = new TradeBigdataDto();
- if (dataArray != null) {
- JSONArray innerArray = dataArray.getJSONArray(0);
- String sellVol = innerArray.getString(1);
- String buyVol = innerArray.getString(2);
- String ts = innerArray.getString(0);
- tradeBigdataDto.setBuyVol(buyVol);
- tradeBigdataDto.setSellVol(sellVol);
- tradeBigdataDto.setTs(ts);
- }
- return new FebsResponse().data(tradeBigdataDto);
- }catch (Exception e){
- return null;
- }
- }
-
- @Override
- public FebsResponse getPositionRatio(ApiValidApiMessageDto apiValidApiMessageDto) {
- log.info("getPositionRatio:{}", apiValidApiMessageDto);
-
- String coinName = apiValidApiMessageDto.getCoinName();// String coinName = "BTC";
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(
- ZhangHuEnum.JIAOYISUO.getValue()
- );
- // 检查API消息信息是否存在
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("API_MESSAGE信息未设置");
- }
-
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 构建查询余额的参数
- LinkedHashMap<String, Object> positionsParameters = new LinkedHashMap<>();
- positionsParameters.put("period", "4H");
- positionsParameters.put("instId", coinName+"-USDT-SWAP");
- positionsParameters.put("limit", "1");
- try{
- // 发送签名请求获取余额信息
- String positionRatio = okxAccount.requestHandler.sendSignedRequest(
- okxAccount.baseUrl,
- OKXContants.POSITIONRATIO,
- positionsParameters,
- HttpMethod.GET,
- okxAccount.isSimluate());
- // 记录余额信息日志
- log.info("positionRatio:{}", positionRatio);
- JSONObject balanceJson = JSON.parseObject(positionRatio);
- String code = balanceJson.getString("code");
- if(!"0".equals(code)){
- return null;
- }
- JSONArray dataArray = balanceJson.getJSONArray("data");
- TradeBigdataDto tradeBigdataDto = new TradeBigdataDto();
- if (dataArray != null) {
- JSONArray innerArray = dataArray.getJSONArray(0);
- String longShortAcctRatio = innerArray.getString(1);
- String ts = innerArray.getString(0);
- tradeBigdataDto.setLongShortAcctRatio(longShortAcctRatio);
- tradeBigdataDto.setTs(ts);
- }
- return new FebsResponse().data(tradeBigdataDto);
- }catch (Exception e){
- return null;
- }
- }
-
- @Override
- public FebsResponse getPositionTradingvolume(ApiValidApiMessageDto apiValidApiMessageDto) {
- log.info("getPositionTradingvolume:{}", apiValidApiMessageDto);
-
- String coinName = apiValidApiMessageDto.getCoinName();// String coinName = "BTC";
- QuantApiMessage quantApiMessage = apiMessageService.getApiMessage(
- ZhangHuEnum.JIAOYISUO.getValue()
- );
- // 检查API消息信息是否存在
- if(ObjectUtil.isEmpty(quantApiMessage)){
- throw new FebsException("API_MESSAGE信息未设置");
- }
-
- // 初始化账户对象
- OKXAccount okxAccount = this.initAccount(quantApiMessage);
-
- // 构建查询余额的参数
- LinkedHashMap<String, Object> positionsParameters = new LinkedHashMap<>();
- positionsParameters.put("period", "1D");
- positionsParameters.put("ccy", coinName);
- positionsParameters.put("limit", "1");
- try{
- // 发送签名请求获取余额信息
- String positionTradingvolume = okxAccount.requestHandler.sendSignedRequest(
- okxAccount.baseUrl,
- OKXContants.POSITIONVOLUME,
- positionsParameters,
- HttpMethod.GET,
- okxAccount.isSimluate());
- // 记录余额信息日志
- log.info("positionTradingvolume:{}", positionTradingvolume);
- JSONObject balanceJson = JSON.parseObject(positionTradingvolume);
- String code = balanceJson.getString("code");
- if(!"0".equals(code)){
- return null;
- }
- JSONArray dataArray = balanceJson.getJSONArray("data");
- TradeBigdataDto tradeBigdataDto = new TradeBigdataDto();
- if (dataArray != null) {
- JSONArray innerArray = dataArray.getJSONArray(0);
- String oi = innerArray.getString(1);
- String vol = innerArray.getString(2);
- String ts = innerArray.getString(0);
- tradeBigdataDto.setOi(oi);
- tradeBigdataDto.setVol(vol);
- tradeBigdataDto.setTs(ts);
- }
- return new FebsResponse().data(tradeBigdataDto);
- }catch (Exception e){
- return null;
- }
- }
-
- //此方法用于验证账号
- private boolean validateAccount(ApiMessageDto apiMessageDto) throws Exception {
- boolean flag = false;
-// try {
- //设置请求
- URL url = new URL(baseurl+"/api/v5/account/balance");
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-
- //设置请求方法
- connection.setRequestMethod("GET");
-
- //设置必需的头信息
- long now = System.currentTimeMillis() / 1000;
- String timestamp = String.valueOf(now);
- String preHash = timestamp + "GET" + "/api/v5/account/balance"; //URL路径
- String signature = generateSignature(preHash, apiMessageDto.getBSecretkey());
-
- connection.setRequestProperty("OK-ACCESS-KEY", apiMessageDto.getASecretkey());
- connection.setRequestProperty("OK-ACCESS-SIGN", signature);
- connection.setRequestProperty("OK-ACCESS-TIMESTAMP", timestamp);
- connection.setRequestProperty("OK-ACCESS-PASSPHRASE", apiMessageDto.getPassPhrass());
-
- connection.setRequestProperty("Content-Type", "application/json");
-
- //执行请求
- int responseCode = connection.getResponseCode();
- BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- String inputLine;
- StringBuffer response = new StringBuffer();
-
- while ((inputLine = in.readLine()) != null) {
- response.append(inputLine);
- }
- in.close();
-
- //打印响应
- if(responseCode == 200){
- flag = true;
- } else {
- flag = false;
- }
-// } catch (Exception e) {
-// //在此打印异常信息
-// log.error("Exception: " + e.getMessage());
-// flag = false;
-// }
- return flag;
- }
-
- //此方法用于生成签名
- private static String generateSignature(String preHash, String secretKey) throws Exception{
- javax.crypto.Mac sha256_HMAC = javax.crypto.Mac.getInstance("HmacSHA256");
- javax.crypto.spec.SecretKeySpec secret_key = new javax.crypto.spec.SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
- sha256_HMAC.init(secret_key);
- return Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(preHash.getBytes()));
- }
-
- public static void main(String[] args) throws Exception {
- String buySellSituation = "{\"code\":\"0\",\"data\":[[\"1718164800000\",\"52000.2999999999975\",\"60671.0000000000019\"]],\"msg\":\"\"}";
- log.info("buySellSituation:{}", buySellSituation);
- JSONObject balanceJson = JSON.parseObject(buySellSituation);
- JSONArray dataArray = balanceJson.getJSONArray("data");
- TradeBigdataDto tradeBigdataDto = new TradeBigdataDto();
- if (dataArray != null) {
- JSONArray innerArray = dataArray.getJSONArray(0);
- String sellVol = innerArray.getString(1);
- String buyVol = innerArray.getString(2);
- String ts = innerArray.getString(0);
- tradeBigdataDto.setBuyVol(buyVol);
- tradeBigdataDto.setSellVol(sellVol);
- tradeBigdataDto.setTs(ts);
- }
- System.out.println(tradeBigdataDto.toString());
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ApiAccountHoldVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ApiAccountHoldVo.java
deleted file mode 100644
index 88c5367..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ApiAccountHoldVo.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Data
-@ApiModel(value = "ApiAccountHoldVo", description = "列表")
-public class ApiAccountHoldVo {
-
- @ApiModelProperty(value = "总金额")
- private BigDecimal totalBalance = BigDecimal.ZERO;
- @ApiModelProperty(value = "盈亏比")
- private BigDecimal totalPercent = BigDecimal.ZERO;
- @ApiModelProperty(value = "可用金额")
- private BigDecimal availableBalance = BigDecimal.ZERO;
- @ApiModelProperty(value = "持仓金额")
- private BigDecimal holdBalance = BigDecimal.ZERO;
- @ApiModelProperty(value = "占用保证金")
- private BigDecimal useBalance = BigDecimal.ZERO;
-
- @ApiModelProperty(value = "币种余额")
- private BigDecimal cashBal = BigDecimal.ZERO;
-
- @ApiModelProperty(value = "可用保证金")
- private BigDecimal availEq = BigDecimal.ZERO;
-
- @ApiModelProperty(value = "币种占用金额")
- private BigDecimal frozenBal = BigDecimal.ZERO;
-
- @ApiModelProperty(value = "币种全仓保证金率")
- private String mgnRatio;
-
- @ApiModelProperty(value = "当前所需起始保证金")
- private BigDecimal initialMargin;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ApiPositionsInfoVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ApiPositionsInfoVo.java
deleted file mode 100644
index 671c1c8..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ApiPositionsInfoVo.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-@Data
-@ApiModel(value = "ApiPositionsInfoVo", description = "持仓信息")
-public class ApiPositionsInfoVo implements Serializable {
-
- @ApiModelProperty(value = "开仓均价")
- private BigDecimal avgPx = BigDecimal.ZERO;
- @ApiModelProperty(value = "未实现盈亏")
- private BigDecimal upl = BigDecimal.ZERO;
- @ApiModelProperty(value = "盈亏平衡价")
- private BigDecimal bePx = BigDecimal.ZERO;
- @ApiModelProperty(value = "标记价格")
- private BigDecimal markPx = BigDecimal.ZERO;
- @ApiModelProperty(value = "持仓数量")
- private BigDecimal pos = BigDecimal.ZERO;
- @ApiModelProperty(value = "币种")
- private String coinName;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ProductMessVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ProductMessVo.java
deleted file mode 100644
index 6c42884..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/ProductMessVo.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo;
-
-import lombok.Data;
-
-@Data
-public class ProductMessVo {
- // 币种
- private String symbol;
-
- // 下单价格精度
- private String tickSz;
-
- // 下单数量精度
- private String lotSz;
-
- // 最小下单数量
- private String minSz;
-
- // 合约面值
- private String ctVal;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/SinglemarketVo.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/SinglemarketVo.java
deleted file mode 100644
index b169a1c..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/verify/vo/SinglemarketVo.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.okxpi.verify.vo;
-
-import lombok.Data;
-
-@Data
-public class SinglemarketVo {
- // 产品类型
- private String instType;
-
- // 产品ID
- private String instId;
-
- // 最新成交价
- private String last;
-
- // 最新成交的数量,0 代表没有成交量
- private String lastSz;
-
- // 卖一价
- private String askPx;
-
- // 卖一价对应的数量
- private String askSz;
-
- // 买一价
- private String bidPx;
-
- // 买一价对应的数量
- private String bidSz;
-
- // 24小时开盘价
- private String open24h;
-
- // 24小时最高价
- private String high24h;
-
- // 24小时最低价
- private String low24h;
-
- // 24小时成交量,以币为单位
- // 如果是衍生品合约,数值为交易货币的数量。
- // 如果是币币/币币杠杆,数值为计价货币的数量。
- private String volCcy24h;
-
- // 24小时成交量,以张为单位
- // 如果是衍生品合约,数值为合约的张数。
- // 如果是币币/币币杠杆,数值为交易货币的数量。
- private String vol24h;
-
- // UTC+0 时开盘价
- private String sodUtc0;
-
- // UTC+8 时开盘价
- private String sodUtc8;
-
- // ticker数据产生时间,Unix时间戳的毫秒数格式,如 1597026383085
- private String ts;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/FebsException.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/FebsException.java
deleted file mode 100644
index 98219f7..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/FebsException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.utils;
-
-/**
- * FEBS系统内部异常
- *
- * @author MrBird
- */
-public class FebsException extends RuntimeException {
-
- private static final long serialVersionUID = -994962710559017255L;
-
- public FebsException(String message) {
- super(message);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/FebsResponse.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/FebsResponse.java
deleted file mode 100644
index c0e8d12..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/FebsResponse.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.utils;
-
-import org.springframework.http.HttpStatus;
-
-import java.util.HashMap;
-
-/**
- * @author MrBird
- */
-public class FebsResponse extends HashMap<String, Object> {
-
- private static final long serialVersionUID = -8713837118340960775L;
-
- public FebsResponse code(HttpStatus status) {
- this.put("code", status.value());
- return this;
- }
-
- public FebsResponse message(String message) {
- this.put("message", message);
- return this;
- }
-
- public FebsResponse data(Object data) {
- this.put("data", data);
- return this;
- }
-
- public FebsResponse success() {
- this.code(HttpStatus.OK);
- return this;
- }
-
- public FebsResponse fail() {
- this.code(HttpStatus.INTERNAL_SERVER_ERROR);
- return this;
- }
-
- @Override
- public FebsResponse put(String key, Object value) {
- super.put(key, value);
- return this;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/SSLConfig.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/SSLConfig.java
deleted file mode 100644
index 2187807..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/SSLConfig.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.utils;
-
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import java.security.SecureRandom;
-
-/**
- * @author Administrator
- */
-public class SSLConfig {
- public static void configureSSL() {
- try {
- // 配置SSL上下文
- SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
- sslContext.init(null, null, new SecureRandom());
-
- // 设置默认SSL套接字工厂
- HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/SignUtils.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/SignUtils.java
deleted file mode 100644
index 87dfb2c..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/SignUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.utils;
-
-import lombok.extern.slf4j.Slf4j;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import java.util.Base64;
-
-
-@Slf4j
-public class SignUtils {
-
- public static String signRest(String secretKey, String timestamp, String method, String path, String body) {
- String str = String.format("%s%s%s%s",
- timestamp, // timestamp
- method, // method GET/POST
- path, // requestPath
- body // body
- );
- try {
- return Base64.getEncoder().encodeToString(hmacSHA256(secretKey.getBytes(), str.getBytes()));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
-
-
- /**
- * HmacSHA256算法,返回的结果始终是32位
- *
- * @param key 加密的键,可以是任何数据
- * @param content 待加密的内容
- * @return 加密后的内容
- * @throws Exception ex
- */
- public static byte[] hmacSHA256(byte[] key, byte[] content) throws Exception {
- Mac hmacSha256 = Mac.getInstance("HmacSHA256");
- hmacSha256.init(new SecretKeySpec(key, 0, key.length, "HmacSHA256"));
- return hmacSha256.doFinal(content);
- }
-
- public static String signWebsocket(String timestamp, String secretKey) {
- String str = String.format("%s%s%s",
- timestamp,
- "GET",
- "/users/self/verify");
- try {
- return Base64.getEncoder().encodeToString(hmacSHA256(secretKey.getBytes(), str.getBytes()));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/WsMapBuild.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/WsMapBuild.java
deleted file mode 100644
index bb31a95..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/WsMapBuild.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.utils;
-
-import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.Map;
-
-/**
- * @author Administrator
- */
-@Slf4j
-public class WsMapBuild {
-
- public static boolean saveBigDecimalToMap(Map<String,BigDecimal> accountMap, String key, BigDecimal value) {
- try {
- accountMap.put(key, value);
- return true;
- } catch (Exception e) {
- log.error("保存账户数据到MAP 失败", e);
- return false;
- }
- }
-
- public static boolean saveStringToMap(Map<String,String> accountMap, String key, String value) {
- try {
- accountMap.put(key, value);
- return true;
- } catch (Exception e) {
- log.error("保存账户数据到MAP 失败", e);
- return false;
- }
- }
-
-
- /**
- * 安全地将字符串解析为 BigDecimal 类型
- *
- * @param value 字符串数值
- * @return 解析后的 BigDecimal 对象,若解析失败则返回 null
- */
- public static BigDecimal parseBigDecimalSafe(String value) {
- if (value == null || value.isEmpty()) {
- return new BigDecimal(0);
- }
- return new BigDecimal(value).setScale(Integer.parseInt(CoinEnums.TICKSZ.getCode()), RoundingMode.DOWN);
- }
-
- /**
- * 安全地将字符串解析为 BigDecimal 类型
- *
- * @param value 字符串数值
- * @return 解析后的 BigDecimal 对象,若解析失败则返回 null
- */
- public static String parseStringSafe(String value) {
- if (value == null || value.isEmpty()) {
- return "0";
- }
- return value;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/WsParamBuild.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/WsParamBuild.java
deleted file mode 100644
index 082e530..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/utils/WsParamBuild.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.utils;
-
-import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Random;
-
-/**
- * @author Administrator
- */
-public class WsParamBuild {
-
- public static String getOrderNum(String prefix) {
- SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
- String dd=df.format(new Date());
- if (StrUtil.isNotBlank(prefix)) {
- return prefix+dd+getRandomNum(5);
- }
- return dd+getRandomNum(5);
- }
-
- public static String getRandomNum(int length) {
- String str = "0123456789";
- Random random = new Random();
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; ++i) {
- int number = random.nextInt(str.length());
- sb.append(str.charAt(number));
- }
-
- return sb.toString();
- }
-
- public static JSONObject buildJsonObject(String connId, String option, JSONArray argsArray) {
- JSONObject jsonObject = new JSONObject();
- if (StrUtil.isNotEmpty(connId)){
- jsonObject.put("id", connId);
- }
- jsonObject.put("op", option);
- jsonObject.put("args", argsArray);
- return jsonObject;
- }
-
-
- /**
- * 计算购买合约的数量
- *
- * USDT 币本位合约
- * 公式:张数 = 保证金 / (面值 * 标记价格 / 杠杆倍数)
- *
- * @param margin 用户的保证金金额
- * @param leverage 杠杆倍数
- * @param faceValue 合约面值
- * @param markPrice 标记价格
- * @param minLotSz 最小下单精度
- * @return 返回用户可以购买的合约数量
- */
- public static BigDecimal buyCnt(BigDecimal margin, BigDecimal leverage, BigDecimal faceValue, BigDecimal markPrice, int minLotSz) {
- if (margin.compareTo(BigDecimal.ZERO) <= 0 ||
- leverage.compareTo(BigDecimal.ZERO) <= 0 ||
- faceValue.compareTo(BigDecimal.ZERO) <= 0 ||
- markPrice.compareTo(BigDecimal.ZERO) <= 0) {
- return BigDecimal.ZERO;
- }
-
- BigDecimal divisor = markPrice.divide(leverage, 10, BigDecimal.ROUND_DOWN);
- BigDecimal denominator = faceValue.multiply(divisor);
- return margin.divide(denominator, minLotSz, BigDecimal.ROUND_DOWN);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeEnum.java
deleted file mode 100644
index 24f6f87..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeEnum.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.wangge;
-
-/**
- * @author Administrator
- * 网格数据枚举 数据
- * todo 后期考虑优化为可配置项
- */
-
-public enum WangGeEnum {
-
- XIAOSHU_WEISHU("网格价格小数位数", "2"),
- JIAGE_SHANGXIAN("网格上限", "3500"),
- JIAGE_XIAXIAN("网格下限", "2500"),
- JIAN_JU("网格间距", "5")
- ;
-
- private String name;
-
- private String value;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getValue() {
- return value;
- }
-
- public void setValue(String value) {
- this.value = value;
- }
-
- private WangGeEnum(String name, String value) {
- this.name = name;
- this.value = value;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeQueue.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeQueue.java
deleted file mode 100644
index 85dddea..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeQueue.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.wangge;
-
-import com.xcong.excoin.rabbit.pricequeue.AscBigDecimal;
-import com.xcong.excoin.rabbit.pricequeue.DescBigDecimal;
-
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 网格交易队列管理类
- *
- * 用于管理系统中各种网格交易相关的优先级阻塞队列,
- * 包括完整的网格队列、平仓队列和开仓队列。
- *
- * @author Administrator
- */
-public class WangGeQueue {
-
- //------------------------------------------------------------------------------------------------------------------
- //------------------------------------------------------------------------------------------------------------------
- // todo 系统启动后,初始化网格队列
- /**
- * 完整的网格 头元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> QUEUE_ASC = null;
-
-
- //------------------------------------------------------------------------------------------------------------------
- //------------------------------------------------------------------------------------------------------------------
- // todo 当用户下了第一单后,根据开仓价格初始化网格平仓队列和开仓队列
- /**
- * 网格平仓队列 头元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> QUEUE_PINGCANG_ASC = null;
-
- /**
- * 网格开仓队列 头元素最大
- */
- public static PriorityBlockingQueue<DescBigDecimal> QUEUE_KAICANG_DESC = null;
-
- /**
- * 获取完整的网格队列(升序)
- * 如果队列未初始化则创建新的优先级阻塞队列
- *
- * @return 返回升序排列的PriorityBlockingQueue队列,队列头部元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> getQueueAsc() {
- if (QUEUE_ASC == null) {
- QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return QUEUE_ASC;
- }
-
- /**
- * 获取网格平仓队列(升序)
- * 如果队列未初始化则创建新的优先级阻塞队列
- *
- * @return 返回升序排列的PriorityBlockingQueue队列,队列头部元素最小
- */
- public static PriorityBlockingQueue<AscBigDecimal> getPingCang() {
- if (QUEUE_PINGCANG_ASC == null) {
- QUEUE_PINGCANG_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return QUEUE_PINGCANG_ASC;
- }
-
- /**
- * 获取网格开仓队列(降序)
- * 如果队列未初始化则创建新的优先级阻塞队列
- *
- * @return 返回降序排列的PriorityBlockingQueue队列,队列头部元素最大
- */
- public static PriorityBlockingQueue<DescBigDecimal> getKaiCang() {
- if (QUEUE_KAICANG_DESC == null) {
- QUEUE_KAICANG_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return QUEUE_KAICANG_DESC;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeService.java
deleted file mode 100644
index 9b240bb..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.wangge;
-
-import com.xcong.excoin.rabbit.pricequeue.AscBigDecimal;
-import com.xcong.excoin.rabbit.pricequeue.DescBigDecimal;
-
-import java.math.BigDecimal;
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 网格交易服务接口
- * 定义了网格交易的核心操作方法,包括初始化网格、开仓和平仓等操作
- * @author Administrator
- */
-public interface WangGeService {
-
- /**
- * 初始化网格交易
- * 创建并初始化用于网格交易的价格队列,按照价格升序排列
- * @return 初始化结果信息,返回按价格升序排列的阻塞队列
- */
- PriorityBlockingQueue<AscBigDecimal> initWangGe();
-
- /**
- * 初始化开仓操作
- * 根据指定价格初始化开仓队列,将开仓价格点加入到价格队列中
- * @param jiaGe 开仓价格
- * @param queueAsc 价格队列,用于存储按升序排列的价格点
- */
- PriorityBlockingQueue<DescBigDecimal> initKaiCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc);
-
- /**
- * 初始化平仓操作
- * 根据指定价格初始化平仓队列,将平仓价格点加入到价格队列中
- * @param jiaGe 开仓价格
- * @param queueAsc 价格队列,用于存储按升序排列的价格点
- */
- PriorityBlockingQueue<AscBigDecimal> initPingCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc);
-
-
-}
-
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeServiceImpl.java
deleted file mode 100644
index 02371a7..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/wangge/WangGeServiceImpl.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.wangge;
-
-import com.xcong.excoin.rabbit.pricequeue.AscBigDecimal;
-import com.xcong.excoin.rabbit.pricequeue.DescBigDecimal;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 网格交易服务实现类,用于初始化价格网格、开仓和平仓操作。
- *
- * @author Administrator
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class WangGeServiceImpl implements WangGeService {
-
- /**
- * 初始化价格网格队列。根据配置的价格上限、下限和间隔生成一系列价格点,
- * 并将这些价格点存入升序优先阻塞队列中。
- *
- * @return 返回初始化完成的升序价格队列;若初始化失败则返回null
- */
- @Override
- public PriorityBlockingQueue<AscBigDecimal> initWangGe() {
- log.info("网格初始化中");
- PriorityBlockingQueue<AscBigDecimal> queueAsc = WangGeQueue.getQueueAsc();
- queueAsc.clear();
-
- String shangxianValue = WangGeEnum.JIAGE_SHANGXIAN.getValue();
- String xiaxianValue = WangGeEnum.JIAGE_XIAXIAN.getValue();
- String jianjuValue = WangGeEnum.JIAN_JU.getValue();
- String weishuValueStr = WangGeEnum.XIAOSHU_WEISHU.getValue();
-
- try {
- BigDecimal shangxian = new BigDecimal(shangxianValue);
- BigDecimal xiaxian = new BigDecimal(xiaxianValue);
- BigDecimal jianju = new BigDecimal(jianjuValue);
-
- if (jianju.compareTo(BigDecimal.ZERO) == 0) {
- log.error("价格间隔不能为0");
- return null;
- }
-
- int weishu = Integer.parseInt(weishuValueStr);
- BigDecimal diff = shangxian.subtract(xiaxian);
- int count = diff.divide(jianju, 0, RoundingMode.DOWN).intValue();
-
- BigDecimal currentStep = BigDecimal.ZERO;
- for (int i = 0; i <= count; i++) {
- BigDecimal stepMultiplier = currentStep.multiply(jianju);
- BigDecimal wangGeJiaGe = xiaxian.add(stepMultiplier).setScale(weishu, RoundingMode.DOWN);
- AscBigDecimal ascBigDecimal = new AscBigDecimal(wangGeJiaGe.toString());
- queueAsc.add(ascBigDecimal);
- currentStep = currentStep.add(BigDecimal.ONE);
- }
-
- if (queueAsc.isEmpty()) {
- log.info("网格初始化失败");
- return null;
- }
-
- log.info("网格初始化成功");
- return queueAsc;
- } catch (NumberFormatException e) {
- log.error("解析价格参数失败", e);
- return null;
- } catch (Exception e) {
- log.error("初始化网格发生未知异常", e);
- return null;
- }
- }
-
- /**
- * 根据当前价格初始化开仓队列。遍历已有的升序价格队列,
- * 将小于当前价格的所有价格点加入降序的开仓队列中。
- *
- * @param jiaGe 当前价格
- * @param queueAsc 已初始化的价格升序队列
- */
- @Override
- public PriorityBlockingQueue<DescBigDecimal> initKaiCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc) {
- PriorityBlockingQueue<DescBigDecimal> queueKaiCang = WangGeQueue.getKaiCang();
- queueKaiCang.clear();
-
- AscBigDecimal now = new AscBigDecimal(jiaGe.toString());
-
- for (AscBigDecimal ascBigDecimal : queueAsc) {
- if (ascBigDecimal.compareTo(now) < 0) {
- DescBigDecimal kaiCangJia = new DescBigDecimal(ascBigDecimal.getValue().toString());
- queueKaiCang.add(kaiCangJia);
- }
- }
-
- return queueKaiCang;
- }
-
- /**
- * 根据当前价格初始化平仓队列。遍历已有的升序价格队列,
- * 将大于当前价格的所有价格点加入升序的平仓队列中。
- *
- * @param jiaGe 当前价格
- * @param queueAsc 已初始化的价格升序队列
- */
- @Override
- public PriorityBlockingQueue<AscBigDecimal> initPingCang(BigDecimal jiaGe, PriorityBlockingQueue<AscBigDecimal> queueAsc) {
- PriorityBlockingQueue<AscBigDecimal> queuePingCang = WangGeQueue.getPingCang();
- queuePingCang.clear();
-
- AscBigDecimal now = new AscBigDecimal(jiaGe.toString());
-
- for (AscBigDecimal ascBigDecimal : queueAsc) {
- if (ascBigDecimal.compareTo(now) > 0) {
- queuePingCang.add(ascBigDecimal);
- }
- }
-
- return queuePingCang;
- }
-
- /**
- * 主方法,用于测试网格初始化及开仓/平仓逻辑。
- * 示例使用固定价格"0.355"进行模拟调用。
- *
- * @param args 启动参数(未使用)
- */
- public static void main(String[] args) {
- for (int i = 0; i < 10; i++) {
- WangGeServiceImpl wangGeService = new WangGeServiceImpl();
- PriorityBlockingQueue<AscBigDecimal> queueAsc = wangGeService.initWangGe();
- if (queueAsc != null) {
- wangGeService.initKaiCang(new BigDecimal("91000"), queueAsc);
- wangGeService.initPingCang(new BigDecimal("91000"), queueAsc);
- }
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/ApiMessageServiceImpl.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/ApiMessageServiceImpl.java
deleted file mode 100644
index c8b8f0e..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/ApiMessageServiceImpl.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.zhanghu;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.ExchangeInfoEnum;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class ApiMessageServiceImpl implements IApiMessageService {
-
- @Override
- public QuantApiMessage getApiMessage(String okx) {
-
- QuantApiMessage quantApiMessage = new QuantApiMessage();
- quantApiMessage.setExchange(okx);
- quantApiMessage.setMemberId(1L);
-
- // 根据传入的账号名称获取对应的账号信息
- ExchangeInfoEnum account = ExchangeInfoEnum.valueOf(okx);
- quantApiMessage.setAccountType(account.isAccountType()? "true":"false");
- quantApiMessage.setState(1);
- quantApiMessage.setIsTrade(1);
- quantApiMessage.setASecretkey(account.getApiKey());
- quantApiMessage.setBSecretkey(account.getSecretKey());
- quantApiMessage.setPassPhrass(account.getPassphrase());
- return quantApiMessage;
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/IApiMessageService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/IApiMessageService.java
deleted file mode 100644
index 73ec98d..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/IApiMessageService.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.zhanghu;
-
-import com.xcong.excoin.modules.okxNewPrice.okxpi.config.Dto.QuantApiMessage;
-
-
-public interface IApiMessageService{
-
- QuantApiMessage getApiMessage(String okx);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/ZhangHuEnum.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/ZhangHuEnum.java
deleted file mode 100644
index 3647e8b..0000000
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/zhanghu/ZhangHuEnum.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.xcong.excoin.modules.okxNewPrice.zhanghu;
-
-/**
- * @author Administrator
- */
-
-public enum ZhangHuEnum {
- JIAOYISUO("交易所名字", "OKX"),
- zhanghu_zongjine("账户总资金", "1000"),
- baozhengjine("账户下单总保证金", "300"),
- meicixiadanjine("每次下单金额", "30"),
- ;
-
- private String name;
-
- private String value;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getValue() {
- return value;
- }
-
- public void setValue(String value) {
- this.value = value;
- }
-
- private ZhangHuEnum(String name, String value) {
- this.name = name;
- this.value = value;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/controller/PlatformController.java b/src/main/java/com/xcong/excoin/modules/platform/controller/PlatformController.java
deleted file mode 100644
index ccd9d98..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/controller/PlatformController.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.xcong.excoin.modules.platform.controller;
-
-import javax.annotation.Resource;
-
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.service.PlatformBannerService;
-import com.xcong.excoin.modules.platform.service.PlatformNoticeService;
-import com.xcong.excoin.modules.platform.service.PlatformCnyUsdtExchangeService;
-import com.xcong.excoin.modules.platform.service.PlatformPaymentMethodService;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import lombok.extern.slf4j.Slf4j;
-
-@RestController
-@Slf4j
-@RequestMapping(value = "/api/exchange")
-@Api(value = "PlatformController", tags = "平台系统设置类")
-public class PlatformController {
-
- @Resource
- PlatformCnyUsdtExchangeService platformCnyUsdtExchangeService;
- @Resource
- PlatformPaymentMethodService platformPaymentMethodService;
-
- @Resource
- PlatformBannerService platformBannerService;
-
- @Resource
- PlatformNoticeService PlatformNoticeService;
-
-
- @ApiOperation(value = "findUsdtCnyExchange", notes = "Cny|Usdt兑换")
- @GetMapping(value = "/findUsdtCnyExchange")
- public Result findUsdtCnyExchange(@ApiParam(name = "type", value = "类型", type="string", required=true) @RequestParam("type") String type) {
- log.info("type值----->{}", type);
- return platformCnyUsdtExchangeService.findUsdtCnyExchange(type);
- }
-
- @ApiOperation(value = "findAllPaymentMethod", notes = "查询平台收款方式")
- @GetMapping(value = "/findAllPaymentMethod")
- public Result findAllPaymentMethod() {
- return platformPaymentMethodService.findAll();
- }
-
- @ApiOperation(value = "首页轮播图", notes = "首页轮播图")
- @GetMapping(value = "/findPlatformBannerList")
- public Result findPlatformBannerList() {
- return platformBannerService.findAll();
- }
-
- @ApiOperation(value = "首页公告查询", notes = "首页公告查询")
- @GetMapping(value = "/findPlatformNoticeList")
- public Result findPlatformNoticeList() {
- return PlatformNoticeService.findPlatformNoticeList();
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformBannerDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformBannerDao.java
deleted file mode 100644
index 47bfb50..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformBannerDao.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.platform.entity.PlatformBannerEntity;
-
-public interface PlatformBannerDao extends BaseMapper<PlatformBannerEntity> {
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformCnyUsdtExchangeDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformCnyUsdtExchangeDao.java
deleted file mode 100644
index 59171d1..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformCnyUsdtExchangeDao.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.platform.entity.PlatformCnyUsdtExchangeEntity;
-
-import java.math.BigDecimal;
-
-public interface PlatformCnyUsdtExchangeDao extends BaseMapper<PlatformCnyUsdtExchangeEntity> {
-
- PlatformCnyUsdtExchangeEntity getCNYAndUSDTOne();
-
- void updateUsdt(BigDecimal value);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformFeeSettingDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformFeeSettingDao.java
deleted file mode 100644
index 03ea822..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformFeeSettingDao.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.platform.entity.PlatformFeeSettingEntity;
-
-public interface PlatformFeeSettingDao extends BaseMapper<PlatformFeeSettingEntity> {
-
- PlatformFeeSettingEntity getFeeSettingByTypeAndSymbolLable(@Param("type")Integer type,@Param("symbol")String symbol,@Param("lable")String lable);
-
- PlatformFeeSettingEntity getFeeSettingByTypeAndSymbol(@Param("type")Integer type,@Param("symbol")String symbol);
-
- List<PlatformFeeSettingEntity> getFeeSettingsByTypeAndSymbol(@Param("type")int i,@Param("symbol")String symbol);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformNoticeDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformNoticeDao.java
deleted file mode 100644
index 5625867..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformNoticeDao.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.platform.entity.PlatformNoticeEntity;
-
-public interface PlatformNoticeDao extends BaseMapper<PlatformNoticeEntity> {
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformPaymentMethodDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformPaymentMethodDao.java
deleted file mode 100644
index ecabe6d..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformPaymentMethodDao.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.platform.entity.PlatformPaymentMethodEntity;
-
-public interface PlatformPaymentMethodDao extends BaseMapper<PlatformPaymentMethodEntity> {
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformSymbolsCoinDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformSymbolsCoinDao.java
deleted file mode 100644
index a116b5a..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformSymbolsCoinDao.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import java.util.List;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.parameter.vo.MemberCoinAddressCountVo;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsCoinEntity;
-
-public interface PlatformSymbolsCoinDao extends BaseMapper<PlatformSymbolsCoinEntity> {
-
- List<MemberCoinAddressCountVo> selectCoinAddressCount(Long memberId);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformSymbolsSkuDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformSymbolsSkuDao.java
deleted file mode 100644
index cf6399b..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/PlatformSymbolsSkuDao.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.member.parameter.vo.MemberCoinAddressCountVo;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsCoinEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsSkuEntity;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-public interface PlatformSymbolsSkuDao extends BaseMapper<PlatformSymbolsSkuEntity> {
-
- PlatformSymbolsSkuEntity findSymbolSkuByName(@Param("name") String name);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/dao/TradeSettingDao.java b/src/main/java/com/xcong/excoin/modules/platform/dao/TradeSettingDao.java
deleted file mode 100644
index aec081a..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/dao/TradeSettingDao.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.xcong.excoin.modules.platform.dao;
-
-import java.util.List;
-
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsSkuEntity;
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.platform.entity.PlatformLeverageSettingEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-
-public interface TradeSettingDao extends BaseMapper<PlatformTradeSettingEntity> {
-
- PlatformTradeSettingEntity findTradeSetting();
-
- PlatformSymbolsSkuEntity findSymbolSkubySymbol(@Param("symbol") String symbol);
-
- List<PlatformSymbolsSkuEntity> findAllSymbolSkubySymbol();
-
- List<PlatformLeverageSettingEntity> findLeverageSetting();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformBannerEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformBannerEntity.java
deleted file mode 100644
index 6a511c6..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformBannerEntity.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-
-import lombok.Data;
-@Data
-@TableName("platform_banner")
-public class PlatformBannerEntity extends BaseEntity{
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- /**
- * 标题
- */
- private String name;
- /**
- * 图片链接
- */
- private String imageUrl;
- /**
- * 是否可跳转 1-是2-否
- */
- private String isJump;
- /**
- * 跳转外部或内部 1-内2-外
- */
- private int isInside;
- /**
- * 跳转链接
- */
- private String jumpUrl;
- /**
- * 显示端口 1-pc2-手机
- */
- private int showPort;
- /**
- * 联系方式
- */
- private String sort;
- /**
- * 是否置顶 1-是2-否
- */
- private String isTop;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformCnyUsdtExchangeEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformCnyUsdtExchangeEntity.java
deleted file mode 100644
index 4afacaf..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformCnyUsdtExchangeEntity.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-
-import lombok.Data;
-@Data
-@TableName("platform_cny_usdt_exchange")
-public class PlatformCnyUsdtExchangeEntity implements Serializable {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- private Long id;
-
- /**
- * 兑换比例
- */
- private BigDecimal value;
- /**
- * 增减偏量
- */
- private BigDecimal diff;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformFeeSettingEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformFeeSettingEntity.java
deleted file mode 100644
index ecea14f..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformFeeSettingEntity.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-
-import lombok.Data;
-
-@Data
-@TableName("platform_fee_setting")
-public class PlatformFeeSettingEntity implements Serializable {
-
- private static final long serialVersionUID = 1L;
- /**
- * 主键ID
- */
- private Long id;
- /**
- * 类型 1-充币2-提币3-充值USDT4-提现USDT
- */
- private Integer type;
- /**
- * 最低价
- */
- private BigDecimal minPrice;
- /**
- * 最高价
- */
- private BigDecimal maxPrice;
- /**
- * 手续费价
- */
- private BigDecimal feePrice;
- /**
- *
- */
- private Date createTime;
- /**
- * 人民币价格
- */
- private BigDecimal cnyPrice;
- /**
- * 币种
- */
- private String symbol;
- /**
- * USDT链名
- */
- private String lable;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformLeverageSettingEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformLeverageSettingEntity.java
deleted file mode 100644
index 8d72d42..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformLeverageSettingEntity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import java.io.Serializable;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-
-import lombok.Data;
-
-/**
- * 杠杆设置表
- */
-@Data
-@TableName("platform_leverage_setting")
-public class PlatformLeverageSettingEntity implements Serializable {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
- /**
- * 杠杆值
- */
- private String value;
- /**
- * 杠杆名称
- */
- private String name;
- /**
- * 币种
- */
- private String symbol;
- /**
- * 维持保证金率
- */
- private String prePriceRate;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformNoticeEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformNoticeEntity.java
deleted file mode 100644
index af6308d..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformNoticeEntity.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-
-import java.util.Date;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-import lombok.Data;
-
-@Data
-@TableName("platform_notice")
-public class PlatformNoticeEntity{
-
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
- /**
- * 标题
- */
- private String title;
-
- /**
- * 类别
- */
- private Integer categoryid;
-
- private String categoryname;
- private String source;
- private String content;
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- private Date createTime;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformPaymentMethodEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformPaymentMethodEntity.java
deleted file mode 100644
index e8a2fff..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformPaymentMethodEntity.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-
-import lombok.Data;
-@Data
-@TableName("platform_payment_method")
-public class PlatformPaymentMethodEntity{
-
-
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
-
- /**
- * 姓名
- */
- private String name;
- /**
- * 账号
- */
- private String account;
- /**
- * 收款二维码
- */
- private String paymentQrcode;
- /**
- * 类型【1、支付宝2、微信3、银行卡】
- */
- private int type;
- /**
- * 银行名
- */
- private String bank;
- /**
- * 状态
- */
- private int status;
- /**
- * 联系方式
- */
- private String phone;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformSymbolsCoinEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformSymbolsCoinEntity.java
deleted file mode 100644
index d3c893e..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformSymbolsCoinEntity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import java.io.Serializable;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-
-import lombok.Data;
-
-/**
- * 币种表
- */
-@Data
-@TableName("platform_symbols_coin")
-public class PlatformSymbolsCoinEntity implements Serializable{
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
- /**
- * 币种名称
- */
- private String name;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformSymbolsSkuEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformSymbolsSkuEntity.java
deleted file mode 100644
index 17b2e0e..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformSymbolsSkuEntity.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-
-import lombok.Data;
-
-/**
- * 币种规格表
- * @author helius
- */
-@Data
-@TableName("platform_symbols_sku")
-public class PlatformSymbolsSkuEntity implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
- /**
- * 币种名称
- */
- private String name;
- /**
- * 规格
- */
- private BigDecimal lotnumber;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformTradeSettingEntity.java b/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformTradeSettingEntity.java
deleted file mode 100644
index b0e342e..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/entity/PlatformTradeSettingEntity.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.xcong.excoin.modules.platform.entity;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-
-import lombok.Data;
-/**
- * 交易设置表
- * @author Administrator
- *
- */
-@Data
-@TableName("platform_trade_setting")
-public class PlatformTradeSettingEntity implements Serializable {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- @TableId(value = "id",type = IdType.AUTO)
- private Long id;
- /**
- * 点差
- */
- private BigDecimal spread;
- /**
- * 杠杆
- */
- private BigDecimal leverageRatio;
- /**
- * 爆仓
- */
- private BigDecimal outstock;
- /**
- * 手续费率
- */
- private BigDecimal feeRatio;
- /**
- * 币币手续费率
- */
- private BigDecimal coinFeeRatio;
- /**
- * 代理返佣比例
- */
- private BigDecimal agentReturnRatio;
- /**
- * 持仓系数
- */
- private BigDecimal doingRatio;
- /**
- * 预估强平价系数
- */
- private BigDecimal forceParam;
-
- /**
- *盈亏难度系数
- */
- private BigDecimal profitParam;
-
- /**
- * 手续费系数
- */
- private BigDecimal feeSpreadRatio;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformBannerService.java b/src/main/java/com/xcong/excoin/modules/platform/service/PlatformBannerService.java
deleted file mode 100644
index 51d6428..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformBannerService.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.xcong.excoin.modules.platform.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.entity.PlatformBannerEntity;
-
-public interface PlatformBannerService extends IService<PlatformBannerEntity> {
-
- public Result findAll();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformCnyUsdtExchangeService.java b/src/main/java/com/xcong/excoin/modules/platform/service/PlatformCnyUsdtExchangeService.java
deleted file mode 100644
index 264f3c3..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformCnyUsdtExchangeService.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.xcong.excoin.modules.platform.service;
-
-import org.springframework.web.bind.annotation.RequestParam;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.entity.PlatformCnyUsdtExchangeEntity;
-
-public interface PlatformCnyUsdtExchangeService extends IService<PlatformCnyUsdtExchangeEntity> {
-
- public Result findUsdtCnyExchange(@RequestParam("type") String type);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformNoticeService.java b/src/main/java/com/xcong/excoin/modules/platform/service/PlatformNoticeService.java
deleted file mode 100644
index ad6f68b..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformNoticeService.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.xcong.excoin.modules.platform.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.entity.PlatformNoticeEntity;
-
-public interface PlatformNoticeService extends IService<PlatformNoticeEntity> {
-
- Result findPlatformNoticeList();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformPaymentMethodService.java b/src/main/java/com/xcong/excoin/modules/platform/service/PlatformPaymentMethodService.java
deleted file mode 100644
index 55edcbc..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformPaymentMethodService.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.xcong.excoin.modules.platform.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.entity.PlatformPaymentMethodEntity;
-
-public interface PlatformPaymentMethodService extends IService<PlatformPaymentMethodEntity> {
-
- public Result findAll();
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformSymbolsSkuService.java b/src/main/java/com/xcong/excoin/modules/platform/service/PlatformSymbolsSkuService.java
deleted file mode 100644
index fe62d33..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/PlatformSymbolsSkuService.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.xcong.excoin.modules.platform.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.entity.PlatformBannerEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsSkuEntity;
-
-public interface PlatformSymbolsSkuService extends IService<PlatformSymbolsSkuEntity> {
-
- public PlatformSymbolsSkuEntity findSymbolSkuByName(String name);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformBannerServiceImpl.java b/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformBannerServiceImpl.java
deleted file mode 100644
index a6e0c72..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformBannerServiceImpl.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.xcong.excoin.modules.platform.service.impl;
-
-import java.util.List;
-
-import javax.annotation.Resource;
-
-import org.springframework.stereotype.Service;
-
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.dao.PlatformBannerDao;
-import com.xcong.excoin.modules.platform.dao.PlatformPaymentMethodDao;
-import com.xcong.excoin.modules.platform.entity.PlatformBannerEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformPaymentMethodEntity;
-import com.xcong.excoin.modules.platform.service.PlatformBannerService;
-
-@Service
-public class PlatformBannerServiceImpl extends ServiceImpl<PlatformBannerDao, PlatformBannerEntity> implements PlatformBannerService{
- @Resource
- PlatformBannerDao platformBannerDao;
-
- @Override
- public Result findAll() {
- QueryWrapper<PlatformBannerEntity> queryWrapper = new QueryWrapper<>();
- List<PlatformBannerEntity> paymentMethodList = platformBannerDao.selectList(queryWrapper);
- return Result.ok(paymentMethodList);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformCnyUsdtExchangeServiceImpl.java b/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformCnyUsdtExchangeServiceImpl.java
deleted file mode 100644
index 701ca20..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformCnyUsdtExchangeServiceImpl.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.xcong.excoin.modules.platform.service.impl;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.Resource;
-
-import com.xcong.excoin.modules.platform.dao.PlatformCnyUsdtExchangeDao;
-import org.springframework.stereotype.Service;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.entity.PlatformCnyUsdtExchangeEntity;
-import com.xcong.excoin.modules.platform.service.PlatformCnyUsdtExchangeService;
-
-@Service
-public class PlatformCnyUsdtExchangeServiceImpl extends ServiceImpl<PlatformCnyUsdtExchangeDao, PlatformCnyUsdtExchangeEntity> implements PlatformCnyUsdtExchangeService{
- @Resource
- PlatformCnyUsdtExchangeDao platformCnyUsdtExchangeDao;
-
- @Override
- public Result findUsdtCnyExchange(String type) {
- // 查询当前兑换价格
- Map<String, Object> map = new HashMap<String, Object>();
- PlatformCnyUsdtExchangeEntity platformCnyUsdtExchangeEntity = platformCnyUsdtExchangeDao.selectById(1);
- BigDecimal cnyUsdt = platformCnyUsdtExchangeEntity.getValue();
- if ("B".equals(type)) {
- // 买的时候提高价格
- map.put("exchange", cnyUsdt.add(platformCnyUsdtExchangeEntity.getDiff()));
- }else {
- // 卖的时候降低
- map.put("exchange", cnyUsdt.subtract(platformCnyUsdtExchangeEntity.getDiff()));
- }
- return Result.ok(map);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformNoticeServiceImpl.java b/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformNoticeServiceImpl.java
deleted file mode 100644
index f4106a1..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformNoticeServiceImpl.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.platform.service.impl;
-
-import java.util.List;
-
-import javax.annotation.Resource;
-
-import org.springframework.stereotype.Service;
-
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.dao.PlatformNoticeDao;
-import com.xcong.excoin.modules.platform.entity.PlatformNoticeEntity;
-import com.xcong.excoin.modules.platform.service.PlatformNoticeService;
-
-@Service
-public class PlatformNoticeServiceImpl extends ServiceImpl<PlatformNoticeDao, PlatformNoticeEntity> implements PlatformNoticeService {
-
- @Resource
- PlatformNoticeDao platformNoticeDao;
-
- @Override
- public Result findPlatformNoticeList() {
- QueryWrapper<PlatformNoticeEntity> queryWrapper = new QueryWrapper<>();
- List<PlatformNoticeEntity> paymentMethodList = platformNoticeDao.selectList(queryWrapper);
- return Result.ok(paymentMethodList);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformPaymentMethodServiceImpl.java b/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformPaymentMethodServiceImpl.java
deleted file mode 100644
index b4a011e..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformPaymentMethodServiceImpl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.platform.service.impl;
-
-import java.util.List;
-
-import javax.annotation.Resource;
-
-import org.springframework.stereotype.Service;
-
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.platform.dao.PlatformPaymentMethodDao;
-import com.xcong.excoin.modules.platform.entity.PlatformPaymentMethodEntity;
-import com.xcong.excoin.modules.platform.service.PlatformPaymentMethodService;
-
-@Service
-public class PlatformPaymentMethodServiceImpl extends ServiceImpl<PlatformPaymentMethodDao, PlatformPaymentMethodEntity> implements PlatformPaymentMethodService{
- @Resource
- PlatformPaymentMethodDao platformPaymentMethodDao;
-
- @Override
- public Result findAll() {
- QueryWrapper<PlatformPaymentMethodEntity> queryWrapper = new QueryWrapper<>();
- List<PlatformPaymentMethodEntity> paymentMethodList = platformPaymentMethodDao.selectList(queryWrapper);
- return Result.ok(paymentMethodList);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformSymbolsSkuServiceImpl.java b/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformSymbolsSkuServiceImpl.java
deleted file mode 100644
index 39c0248..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/service/impl/PlatformSymbolsSkuServiceImpl.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.xcong.excoin.modules.platform.service.impl;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.modules.platform.dao.PlatformSymbolsSkuDao;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsSkuEntity;
-import com.xcong.excoin.modules.platform.service.PlatformSymbolsSkuService;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-
-/**
- * 币种规格服务类
- */
-@Service
-public class PlatformSymbolsSkuServiceImpl extends ServiceImpl<PlatformSymbolsSkuDao, PlatformSymbolsSkuEntity> implements PlatformSymbolsSkuService {
-
- @Resource
- private PlatformSymbolsSkuDao platformSymbolsSkuDao;
-
- @Override
- public PlatformSymbolsSkuEntity findSymbolSkuByName(String name) {
- return platformSymbolsSkuDao.findSymbolSkuByName(name);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/platform/vo/PlatformCnyUsdtExchangeVo.java b/src/main/java/com/xcong/excoin/modules/platform/vo/PlatformCnyUsdtExchangeVo.java
deleted file mode 100644
index 8a06fc6..0000000
--- a/src/main/java/com/xcong/excoin/modules/platform/vo/PlatformCnyUsdtExchangeVo.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.xcong.excoin.modules.platform.vo;
-
-import java.math.BigDecimal;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-@Data
-@ApiModel(value = "会员快捷买入卖出", description = "会员快捷买入卖出类")
-public class PlatformCnyUsdtExchangeVo {
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/controller/SymbolsController.java b/src/main/java/com/xcong/excoin/modules/symbols/controller/SymbolsController.java
deleted file mode 100644
index 64fe133..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/controller/SymbolsController.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.xcong.excoin.modules.symbols.controller;
-
-import com.huobi.client.model.Candlestick;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.symbols.parameter.dto.KlineDetailDto;
-import com.xcong.excoin.modules.symbols.parameter.vo.HomeSymbolsVo;
-import com.xcong.excoin.modules.symbols.parameter.vo.KlineDataVo;
-import com.xcong.excoin.modules.symbols.service.SymbolsService;
-import com.xcong.excoin.utils.RedisUtils;
-import com.xcong.excoin.utils.TypeJudgeUtils;
-import io.swagger.annotations.*;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-/**
- * @author wzy
- * @date 2020-05-28
- **/
-@Api(value = "K线以及币种相关轮询接口类", tags = "K线以及币种相关轮询接口类")
-@Slf4j
-@RestController
-@RequestMapping(value = "/api/symbols")
-public class SymbolsController {
-
- @Resource
- private SymbolsService symbolsService;
-
- @Resource
- private RedisUtils redisUtils;
-
- @ApiOperation(value = "轮询获取app首页币种交易信息", notes = "轮询获取app首页币种交易信息")
- @ApiResponses({
- @ApiResponse(code = 0, message = "success", response = HomeSymbolsVo.class)
- })
- @GetMapping(value = "/homeSymbols")
- public Result homeSymbols(@ApiParam(name = "type", value = "类型1-币币2-合约3-自选", required = true, example = "1") @RequestParam(value = "type") Integer type) {
- return symbolsService.homeSymbols(type);
- }
-
- @ApiOperation(value = "根据币种查询币种当前各种数据", notes = "根据币种查询币种当前各种数据")
- @ApiResponses({
- @ApiResponse(code = 0, message = "success", response = HomeSymbolsVo.class)
- })
- @GetMapping(value = "/findSymbolData")
- public Result findSymbolData(@ApiParam(name = "symbol", value = "币种", required = true, example = "BTC/USDT") @RequestParam(value = "symbol") String symbol) {
- return symbolsService.findSymbolData(symbol);
- }
-
- @ApiOperation(value = "查询历史K线数据", notes = "查询历史K线数据")
- @ApiResponses({
- @ApiResponse(code = 0, message = "success", response = KlineDataVo.class)
- })
- @PostMapping(value = "/klineDetail")
- public Result klineDetail(@RequestBody @Valid KlineDetailDto klineDetailDto) {
- if (!TypeJudgeUtils.klinePeriod(klineDetailDto.getPeriod())) {
- return Result.fail("非法参数");
- }
- return symbolsService.findKlineDetails(klineDetailDto);
- }
-
- @ApiOperation(value = "查询当日最高最低价")
- @GetMapping(value = "/getDayHighAndLow")
- public Result getDayHighAndLow(@ApiParam(name = "symbol", value = "币种", required = true, example = "BTC/USDT") @RequestParam(value = "symbol") String symbol) {
- Candlestick object = (Candlestick) redisUtils.get(symbol);
- return Result.ok(object);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/dao/PlatformSymbolsContractDao.java b/src/main/java/com/xcong/excoin/modules/symbols/dao/PlatformSymbolsContractDao.java
deleted file mode 100644
index 5887d22..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/dao/PlatformSymbolsContractDao.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.xcong.excoin.modules.symbols.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.xcong.excoin.modules.symbols.entity.PlatformSymbolsContractEntity;
-
-import java.util.List;
-
-/**
- *
- * @author wzy
- */
-public interface PlatformSymbolsContractDao extends BaseMapper<PlatformSymbolsContractEntity> {
-
- List<PlatformSymbolsContractEntity> selectAllContractSymbols();
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/entity/PlatformSymbolsContractEntity.java b/src/main/java/com/xcong/excoin/modules/symbols/entity/PlatformSymbolsContractEntity.java
deleted file mode 100644
index 4322b00..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/entity/PlatformSymbolsContractEntity.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.symbols.entity;
-
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-
-import java.io.Serializable;
-
-/**
- * @author wzy
- * @date 2020-05-26
- **/
-@Data
-@TableName("platform_symbols_contract")
-public class PlatformSymbolsContractEntity implements Serializable {
-
- private static final long serialVersionUID = -1L;
-
- private Long id;
-
- private String name;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/parameter/dto/KlineDetailDto.java b/src/main/java/com/xcong/excoin/modules/symbols/parameter/dto/KlineDetailDto.java
deleted file mode 100644
index 32aa355..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/parameter/dto/KlineDetailDto.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.symbols.parameter.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-
-/**
- *
- * @Author wzy
- * @Date 2020/5/28
- **/
-@Data
-@ApiModel(value = "KlineDetailDto", description = "请求K线类")
-public class KlineDetailDto {
-
- @NotNull
- @ApiModelProperty(value = "币种", example = "BTC/USDT")
- private String symbol;
-
- @NotNull
- @ApiModelProperty(value = "k线时长", example = "5min")
- private String period;
-
- @NotNull
- @ApiModelProperty(value = "类型 1-币币2-合约", example = "1")
- private Integer type;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/parameter/vo/HomeSymbolsVo.java b/src/main/java/com/xcong/excoin/modules/symbols/parameter/vo/HomeSymbolsVo.java
deleted file mode 100644
index c607ae1..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/parameter/vo/HomeSymbolsVo.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.xcong.excoin.modules.symbols.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * @author wzy
- * @date 2020-05-28
- **/
-@Data
-@ApiModel(value = "HomeSymbolsVo", description = "首页币种行情返回类")
-public class HomeSymbolsVo {
-
- @ApiModelProperty(value = "币种")
- private String symbol;
-
- @ApiModelProperty("当前价")
- private BigDecimal currentPrice;
-
- @ApiModelProperty("对应人民币转换")
- private BigDecimal cnyPrice;
-
- @ApiModelProperty("成交量")
- private BigDecimal volume;
-
- @ApiModelProperty("涨跌幅")
- private BigDecimal upOrDown;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/parameter/vo/KlineDataVo.java b/src/main/java/com/xcong/excoin/modules/symbols/parameter/vo/KlineDataVo.java
deleted file mode 100644
index 3484e4d..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/parameter/vo/KlineDataVo.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.xcong.excoin.modules.symbols.parameter.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * k线返回类
- *
- * @author wzy
- * @date 2020-05-29
- **/
-@Data
-@ApiModel(value = "KlineDataVo", description = "k线返回类")
-public class KlineDataVo {
-
- @ApiModelProperty(value = "时间")
- private long time;
-
- @ApiModelProperty(value = "开盘指数价")
- private BigDecimal open;
-
- @ApiModelProperty(value = "收盘指数价")
- private BigDecimal high;
-
- @ApiModelProperty(value = "最低指数价")
- private BigDecimal low;
-
- @ApiModelProperty(value = "最高指数价")
- private BigDecimal close;
-
- @ApiModelProperty(value = "成交量张数")
- private BigDecimal volume;
-
- @ApiModelProperty(value = "成交量")
- private BigDecimal amount;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/service/SymbolsService.java b/src/main/java/com/xcong/excoin/modules/symbols/service/SymbolsService.java
deleted file mode 100644
index be91c71..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/service/SymbolsService.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.symbols.service;
-
-
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.symbols.parameter.dto.KlineDetailDto;
-
-/**
- * @author wzy
- * @date 2020-05-26
- **/
-public interface SymbolsService {
-
- public void updateSymbolsKine(String time);
-
- public Result homeSymbols(Integer type);
-
- public Result findSymbolData(String symbol);
-
- public Result findKlineDetails(KlineDetailDto klineDetailDto);
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/symbols/service/impl/SymbolsServiceImpl.java b/src/main/java/com/xcong/excoin/modules/symbols/service/impl/SymbolsServiceImpl.java
deleted file mode 100644
index 95d294a..0000000
--- a/src/main/java/com/xcong/excoin/modules/symbols/service/impl/SymbolsServiceImpl.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package com.xcong.excoin.modules.symbols.service.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSONObject;
-import com.huobi.client.model.Candlestick;
-import com.xcong.excoin.common.contants.AppContants;
-import com.xcong.excoin.common.enumerates.SymbolEnum;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.common.system.mapper.CandlestickMapper;
-import com.xcong.excoin.modules.platform.dao.PlatformCnyUsdtExchangeDao;
-import com.xcong.excoin.modules.platform.entity.PlatformCnyUsdtExchangeEntity;
-import com.xcong.excoin.modules.symbols.parameter.dto.KlineDetailDto;
-import com.xcong.excoin.modules.symbols.parameter.vo.HomeSymbolsVo;
-import com.xcong.excoin.modules.symbols.parameter.vo.KlineDataVo;
-import com.xcong.excoin.modules.symbols.service.SymbolsService;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.RedisUtils;
-import com.xcong.excoin.utils.api.ApiClient;
-import com.xcong.excoin.utils.api.response.Kline;
-import com.xcong.excoin.utils.api.response.KlineResponse;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-26
- **/
-@Slf4j
-@Service
-public class SymbolsServiceImpl implements SymbolsService {
-
- @Resource
- private RedisUtils redisUtils;
-
- @Resource
- private PlatformCnyUsdtExchangeDao platformCnyUsdtExchangeDao;
-
- private static final String API_KEY = "3938f004-bfe31905-f7581c1a-6abe0";
- private static final String API_SECRET = "a0f7a154-ghxertfvbf-6ce2d90c-a0bab";
-
-
- private static volatile ApiClient client;
-
- private static ApiClient getClient() {
- if (client == null) {
- synchronized (ApiClient.class) {
- if (client == null) {
- client = new ApiClient(API_KEY, API_SECRET);
- }
- }
- }
- return client;
- }
-
- @Override
- public void updateSymbolsKine(String time) {
- synchronized (this) {
- //更新币币交易K线历史数据
- for (SymbolEnum symbol : SymbolEnum.values()) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- String[] symbols = symbol.getValue().toLowerCase().split("/");
- ApiClient client = getClient();
- KlineResponse kline = client.kline(symbols[0] + symbols[1], time, 1000 + "");
- if (kline != null) {
- if ("ok".equalsIgnoreCase(kline.getStatus())) {
- List<Kline> klines = (List<Kline>) kline.data;
- List<Candlestick> list = new ArrayList<Candlestick>();
- Candlestick candlestick = null;
- for (Kline kline1 : klines) {
- candlestick = new Candlestick();
- candlestick.setAmount(BigDecimal.valueOf(kline1.getAmount()));
- candlestick.setClose(BigDecimal.valueOf(kline1.getClose()));
- candlestick.setCount(kline1.getCount());
- candlestick.setHigh(BigDecimal.valueOf(kline1.getHigh()));
- candlestick.setLow(BigDecimal.valueOf(kline1.getLow()));
- candlestick.setVolume(BigDecimal.valueOf(kline1.getVol()));
- candlestick.setTimestamp(kline1.getId() * 1000);
- candlestick.setOpen(BigDecimal.valueOf(kline1.getOpen()));
- list.add(candlestick);
- }
-
- if (klines.size() > 0) {
- redisUtils.set("KINE_" + symbol.getValue() + "_" + time, list);
- }
- }
- }
- }
- }
- }
-
- @Override
- public Result homeSymbols(Integer type) {
- List<HomeSymbolsVo> list = new ArrayList<>();
- // 币币行情
- if (AppContants.HOME_SYMBOLS_COIN == type) {
- for (SymbolEnum symbolEnum : SymbolEnum.values()) {
- list.add(getSymbolReturnData(symbolEnum.getValue()));
- }
- // 合约行情
- } else if (AppContants.HOME_SYMBOLS_CONTRACT == type) {
- for (SymbolEnum symbolEnum : SymbolEnum.values()) {
- list.add(getSymbolReturnData(symbolEnum.getValue()));
- }
- // 自选行情
- } else {
-
- }
-
- return Result.ok(list);
- }
-
- @Override
- public Result findSymbolData(String symbol) {
- HomeSymbolsVo homeSymbolsVo = getSymbolReturnData(symbol);
- return Result.ok(homeSymbolsVo);
- }
-
- public HomeSymbolsVo getSymbolReturnData(String symbol) {
- PlatformCnyUsdtExchangeEntity cnyUsdtExchange = platformCnyUsdtExchangeDao.getCNYAndUSDTOne();
- // 获取当日k线数据
- Candlestick symbolObject = (Candlestick) redisUtils.get(symbol);
- // 获取当前币种最新价
- BigDecimal newestPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol)));
- // 获取当日k线的开盘价
- BigDecimal openPrice = symbolObject.getOpen();
-
- BigDecimal upOrDown = newestPrice.subtract(openPrice).divide(openPrice, 8, BigDecimal.ROUND_HALF_UP);
- HomeSymbolsVo homeSymbolsVo = new HomeSymbolsVo();
-
- homeSymbolsVo.setSymbol(symbol);
- homeSymbolsVo.setCurrentPrice(newestPrice);
- homeSymbolsVo.setUpOrDown(upOrDown);
- homeSymbolsVo.setVolume(symbolObject.getAmount());
- if (cnyUsdtExchange != null) {
- BigDecimal cnyPrice = newestPrice.multiply(cnyUsdtExchange.getValue()).setScale(2, BigDecimal.ROUND_HALF_UP);
- homeSymbolsVo.setCnyPrice(cnyPrice);
- }
-
- return homeSymbolsVo;
- }
-
- @Override
- public Result findKlineDetails(KlineDetailDto klineDetailDto) {
- String key = "KINE_{}_{}";
- // 币币k线数据
- if (AppContants.HOME_SYMBOLS_COIN == klineDetailDto.getType()) {
- key = StrUtil.format(key, klineDetailDto.getSymbol(), klineDetailDto.getPeriod());
- // 合约k线数据
- } else {
- key = StrUtil.format(key, klineDetailDto.getSymbol(), klineDetailDto.getPeriod());
- }
-
- Object data = redisUtils.get(key);
- if (data != null) {
- List list = (List) data;
- int length = 0;
- // 默认获取k线900个柱状(超出会报错)
- int size = 900;
-
- if (list.size() > size) {
- length = size - 1;
- } else {
- length = list.size() - 1;
- }
-
- List<KlineDataVo> result = new ArrayList<>(length);
- for (int i = length; i > 0; i--) {
- Candlestick object = (Candlestick) list.get(i);
- KlineDataVo klineDataVo = CandlestickMapper.INSTANCE.toKlineDataVo(object);
- result.add(klineDataVo);
- }
- return Result.ok(result);
- }
- return Result.fail("获取数据失败");
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java b/src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java
deleted file mode 100644
index 0be8a3b..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.xcong.excoin.modules.test.controller;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.common.annotations.UserAuth;
-import com.xcong.excoin.common.response.Result;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.test.dto.TestUserDto;
-import com.xcong.excoin.modules.test.entity.TestUserEntity;
-import com.xcong.excoin.modules.test.mapper.TestUserEntityMapper;
-import com.xcong.excoin.modules.test.service.TestUserService;
-import com.xcong.excoin.modules.test.vo.TestUserVo;
-import com.xcong.excoin.utils.MessageSourceUtils;
-import io.swagger.annotations.*;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-/**
- * @author wzy
- * @date 2020-04-24 15:25
- **/
-@RestController
-@RequestMapping(value = "/test")
-@Slf4j
-@Api(value = "这是测试用类", tags = "这是测试用类")
-public class TestUserController {
-
- @Resource
- private TestUserService testUserService;
-
- @ApiOperation(value = "测试用户分页请求", notes = "说明")
- @ApiResponses({@ApiResponse(code = 0, message = "ok", response = TestUserVo.class)})
- @PostMapping(value = "/findUserInPage")
- public Result findUserInPage(@RequestParam(value = "pageSize", defaultValue = "10") int pageSize,
- @RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
- @RequestBody @Validated TestUserDto testUserDto, @UserAuth MemberEntity memberEntity) {
- log.info("--->{}",SecurityContextHolder.getContext().getAuthentication());
- log.info("----->{}", memberEntity);
- Page<TestUserEntity> page = new Page<>(pageNum, pageSize);
- IPage<TestUserEntity> list = testUserService.page(page);
-
- IPage<TestUserVo> aa = TestUserEntityMapper.INSTANCE.pageEntityToPageVO(list);
- return Result.ok(MessageSourceUtils.getString("111"), aa);
- }
-
-
- @ApiOperation(value = "添加测试用户", notes = "该接口用于添加测试用户")
- @PostMapping(value = "/add")
- public Result add(@RequestBody @Valid TestUserDto testUserDto) {
- TestUserEntity testUserEntity = TestUserEntityMapper.INSTANCE.dtoToEntity(testUserDto);
- boolean flag = testUserService.save(testUserEntity);
- if (flag) {
- return Result.ok("success");
- }
- return Result.fail("fail");
- }
-
- @ApiOperation(value = "修改测试用户", notes = "该接口用户修改测试用户")
- @PostMapping(value = "/modify")
- public Result modify(@RequestBody @Validated TestUserDto testUserDto) {
- TestUserEntity testUserEntity = TestUserEntityMapper.INSTANCE.dtoToEntity(testUserDto);
- log.info("#-------->{}#", testUserEntity);
- boolean flag = testUserService.updateById(testUserEntity);
- if (flag) {
- return Result.ok("success");
- }
- return Result.fail("fail");
- }
-
-
- @ApiOperation(value = "根据ID删除用户", notes = "根据ID删除用户")
- @GetMapping(value = "/del/{id}")
- public Result del(@PathVariable(value = "id") Long id) {
- boolean flag = testUserService.removeById(id);
- if (flag) {
- return Result.ok("success");
- }
- return Result.fail("fail");
- }
-
- @ApiOperation(value = "根据Id查询用户信息", notes = "根据Id查询用户信息")
- @GetMapping(value = "/findById/{id}")
- public Result findById(@ApiParam(name = "id", value = "用户ID", required = true, example = "1") @PathVariable(value = "id") Long id) {
- TestUserEntity testUserEntity = testUserService.getById(id);
- TestUserVo testUserVo = TestUserEntityMapper.INSTANCE.entityToVo(testUserEntity);
- return Result.ok("success", testUserVo);
- }
-
- @ApiOperation(value = "根据Id查询用户信息", notes = "根据Id查询用户信息")
- @GetMapping(value = "/findByIdAndName/{id}/{name}")
- public Result findByIdAndName(@ApiParam(name = "id", value="用户ID", required = true, example = "1") @PathVariable(value = "id") Long id,
- @ApiParam(name = "name", value="用户姓名", required = true, example = "wzy") @PathVariable(value = "name") String name) {
- log.info("---->{}", id);
- log.info("----<{}", name);
- return Result.ok("success");
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java b/src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java
deleted file mode 100644
index eba5557..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xcong.excoin.modules.test.dao;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.test.entity.TestUserEntity;
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface TestUserDao extends BaseMapper<TestUserEntity> {
-
- public List<TestUserEntity> selectAll();
-
- IPage<TestUserEntity> selectInPage(Page<TestUserEntity> page);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java b/src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java
deleted file mode 100644
index fa1d08a..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.xcong.excoin.modules.test.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.Length;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-
-/**
- * @author wzy
- * @date 2020-05-08 10:17
- **/
-@Data
-@ApiModel(value = "testUser参数接收类", description = "findUserInPage 参数接收类")
-public class TestUserDto {
-
- @NotNull(message = "id不能为空")
- @ApiModelProperty(value = "这是名字啊", example = "张三")
- private String name;
-
- @Length(min = 6, max = 16, message = "账号长度需为6-16位")
- @ApiModelProperty(value = "账号", example = "admin")
- private String account;
-
- @NotBlank(message = "密码不能为空")
- @ApiModelProperty(value = "这是密码字段啊", example = "123456")
- private String password;
-
- @ApiModelProperty(value = "这是地址ID", example = "123")
- private Long addressId;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java b/src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java
deleted file mode 100644
index 13a3879..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.xcong.excoin.modules.test.entity;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.xcong.excoin.common.system.base.BaseEntity;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * @author wzy
- * @date 2020-04-24 15:00
- **/
-@EqualsAndHashCode(callSuper = true)
-@Data
-@TableName("test_user")
-public class TestUserEntity extends BaseEntity {
-
- private String name;
-
- private String account;
-
- private String password;
-
- @TableField(exist = false)
- private String aaaaa;
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java b/src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java
deleted file mode 100644
index f116802..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xcong.excoin.modules.test.mapper;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.xcong.excoin.modules.test.dto.TestUserDto;
-import com.xcong.excoin.modules.test.entity.TestUserEntity;
-import com.xcong.excoin.modules.test.vo.TestUserVo;
-import com.xcong.excoin.modules.test.vo.TestVo;
-import org.mapstruct.InheritInverseConfiguration;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-09 15:26
- **/
-@Mapper
-public abstract class TestUserEntityMapper {
- public static final TestUserEntityMapper INSTANCE = Mappers.getMapper(TestUserEntityMapper.class);
-
- public abstract TestUserEntity dtoToEntity(TestUserDto testUserDto);
-
- @Mapping(source = "name", target = "name")
- @Mapping(source = "password", target = "pwd")
- public abstract TestVo entityToTestVo(TestUserEntity testUserEntity);
-
- @Mapping(source = "name", target = "userName")
- public abstract TestUserVo entityToVo(TestUserEntity testUserEntity);
-
- public abstract List<TestUserVo> entityListToVoList(List<TestUserEntity> testUserEntities);
-
- public abstract Page<TestUserVo> pageEntityToPageVO(IPage<TestUserEntity> list);
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java b/src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java
deleted file mode 100644
index 448ffb3..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.xcong.excoin.modules.test.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.xcong.excoin.modules.test.entity.TestUserEntity;
-
-import java.util.List;
-
-/**
- * @author helius
- */
-public interface TestUserService extends IService<TestUserEntity> {
-
- public List<TestUserEntity> findAll();
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java b/src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java
deleted file mode 100644
index ab2b9f2..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xcong.excoin.modules.test.service.impl;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xcong.excoin.modules.test.dao.TestUserDao;
-import com.xcong.excoin.modules.test.entity.TestUserEntity;
-import com.xcong.excoin.modules.test.service.TestUserService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-04-24 15:23
- **/
-@Service
-@Slf4j
-public class TestUserServiceImpl extends ServiceImpl<TestUserDao, TestUserEntity> implements TestUserService {
-
- @Resource
- private TestUserDao testUserDao;
-
- @Override
- public List<TestUserEntity> findAll() {
- return testUserDao.selectAll();
- }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java b/src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java
deleted file mode 100644
index efd4073..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.xcong.excoin.modules.test.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-07 17:24
- **/
-@Data
-@ApiModel(value = "测试", description = "测试用户类")
-public class TestUserVo {
-
- @ApiModelProperty(value = "主键ID")
- private Long id;
-
- @ApiModelProperty(value = "用户姓名")
- private String userName;
-
- @ApiModelProperty(value = "密码")
- private String password;
-
- @ApiModelProperty(value = "12345")
- private List<TestVo> testVo;
-
-}
diff --git a/src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java b/src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java
deleted file mode 100644
index ba344b3..0000000
--- a/src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xcong.excoin.modules.test.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * @author wzy
- * @date 2020-05-08 10:09
- **/
-@Data
-@ApiModel(value = "12345", description = "2222222")
-public class TestVo {
-
- @ApiModelProperty(value = "名字")
- private String name;
-
- @ApiModelProperty(value = "密码")
- private String pwd;
-}
diff --git a/src/main/java/com/xcong/excoin/netty/ChatServer.java b/src/main/java/com/xcong/excoin/netty/ChatServer.java
deleted file mode 100644
index 58f0cd7..0000000
--- a/src/main/java/com/xcong/excoin/netty/ChatServer.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.xcong.excoin.netty;
-
-/**
- * @author wzy
- * @date 2019-05-06
- */
-public interface ChatServer {
- void start() throws Exception;
-
- void shutdown();
-}
diff --git a/src/main/java/com/xcong/excoin/netty/bean/RequestBean.java b/src/main/java/com/xcong/excoin/netty/bean/RequestBean.java
deleted file mode 100644
index 289b4ae..0000000
--- a/src/main/java/com/xcong/excoin/netty/bean/RequestBean.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.xcong.excoin.netty.bean;
-
-
-import java.io.Serializable;
-
-/**
- * @author wzy
- * @email wangdoubleone@gmail.com
- * @date 2019-05-09
- */
-public class RequestBean implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 请求类型
- */
- private String type;
-
- /**
- * 当前通道id
- */
- private String channelId;
-
- /**
- * web端通道ID
- */
- private String reqId;
-
- /**
- * 请求参数
- */
- private String params;
-
- /**
- * 手持端是否同意连接 0-否 1-是
- */
- private String tag;
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getChannelId() {
- return channelId;
- }
-
- public void setChannelId(String channelId) {
- this.channelId = channelId;
- }
-
- public String getParams() {
- return params;
- }
-
- public void setParams(String params) {
- this.params = params;
- }
-
- public String getReqId() {
- return reqId;
- }
-
- public void setReqId(String reqId) {
- this.reqId = reqId;
- }
-
- public String getTag() {
- return tag;
- }
-
- public void setTag(String tag) {
- this.tag = tag;
- }
-
- @Override
- public String toString() {
- return "RequestBean{" +
- "type='" + type + '\'' +
- ", channelId='" + channelId + '\'' +
- ", reqId='" + reqId + '\'' +
- ", params='" + params + '\'' +
- ", tag='" + tag + '\'' +
- '}';
- }
-}
diff --git a/src/main/java/com/xcong/excoin/netty/bean/ResponseBean.java b/src/main/java/com/xcong/excoin/netty/bean/ResponseBean.java
deleted file mode 100644
index b595122..0000000
--- a/src/main/java/com/xcong/excoin/netty/bean/ResponseBean.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.xcong.excoin.netty.bean;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author wzy
- * @date 2020-04-18 16:17
- **/
-public class ResponseBean implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- public static final String SUCCESS = "200";
-
- private String status;
-
- private String type;
-
- private String info;
-
- private String channelId;
-
- private Map<Object, Object> mapInfo = new HashMap<>();
-
- private List<?> row;
-
- public static ResponseBean ok(String type, String info) {
- ResponseBean responseBean = new ResponseBean();
- responseBean.status = SUCCESS;
- responseBean.type = type;
- responseBean.info = info;
- return responseBean;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getInfo() {
- return info;
- }
-
- public void setInfo(String info) {
- this.info = info;
- }
-
- public String getChannelId() {
- return channelId;
- }
-
- public void setChannelId(String channelId) {
- this.channelId = channelId;
- }
-
- public Map<Object, Object> getMapInfo() {
- return mapInfo;
- }
-
- public void setMapInfo(Map<Object, Object> mapInfo) {
- this.mapInfo = mapInfo;
- }
-
- public void putInfo(Object key, Object value) {
- this.mapInfo.put(key, value);
- }
-
- public List<?> getRow() {
- return row;
- }
-
- public void setRow(List<?> row) {
- this.row = row;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/netty/common/ChannelManager.java b/src/main/java/com/xcong/excoin/netty/common/ChannelManager.java
deleted file mode 100644
index 5d158f6..0000000
--- a/src/main/java/com/xcong/excoin/netty/common/ChannelManager.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.xcong.excoin.netty.common;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.netty.bean.ResponseBean;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelId;
-import io.netty.channel.group.ChannelGroup;
-import io.netty.channel.group.DefaultChannelGroup;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * @author wzy
- * @email wangdoubleone@gmail.com
- * @date 2019-05-06
- */
-public class ChannelManager {
-
- private static final ChannelGroup WEBSOCKET_GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
-
- // 当前连接到服务器的通道(tcp和websocket)
- private static final ConcurrentMap<String, ChannelId> CHANNEL_MAP = new ConcurrentHashMap<>();
-
- public static void addWebSocketChannel(Channel channel) {
- WEBSOCKET_GROUP.add(channel);
- CHANNEL_MAP.put(channel.id().asShortText(), channel.id());
- }
-
- public static void removeWebSocketChannel(Channel channel) {
- WEBSOCKET_GROUP.remove(channel);
- CHANNEL_MAP.remove(channel.id().asShortText());
- }
-
- public static Channel findWebSocketChannel(String id){
- ChannelId channelId = CHANNEL_MAP.get(id);
- return WEBSOCKET_GROUP.find(channelId);
- }
-
- public static ChannelGroup getWebSocketGroup() {
- return WEBSOCKET_GROUP;
- }
-
- public static void send2All(Object object, String type) {
- if (WEBSOCKET_GROUP.size() == 0) {
- return;
- }
- ResponseBean responseBean = ResponseBean.ok(type, null);
- responseBean.putInfo("data", object);
- String msg = JSONObject.toJSONString(responseBean);
- WEBSOCKET_GROUP.writeAndFlush(NettyTools.webSocketBytes(msg));
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/netty/common/Contans.java b/src/main/java/com/xcong/excoin/netty/common/Contans.java
deleted file mode 100644
index 1a64913..0000000
--- a/src/main/java/com/xcong/excoin/netty/common/Contans.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xcong.excoin.netty.common;
-
-/**
- * @author wzy
- * @date 2019-05-06
- */
-public class Contans {
-
- public static final String HEART_BEAT = "ping pong pang";
-
- public static final String WEB_REQ_CONNECTION = "000_000";
-
- public static final String HOME_SYMBOLS = "001_001";
-
- public static final String ORDER_COIN_PRE_ORDER_DATA = "002_001";
-
- public static final String ORDER_COIN_FIND_TRUST_ORDER = "002_002";
-
- public static final String ORDER_PRE_ORDER_DATA = "003_001";
-
- public static final String ORDER_FIND_TRUST_ORDER = "003_002";
-
-}
diff --git a/src/main/java/com/xcong/excoin/netty/common/NettyTools.java b/src/main/java/com/xcong/excoin/netty/common/NettyTools.java
deleted file mode 100644
index ead90db..0000000
--- a/src/main/java/com/xcong/excoin/netty/common/NettyTools.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.xcong.excoin.netty.common;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
-
-/**
- * @author wzy
- * @date 2019-05-14
- */
-public class NettyTools {
-
-
- /**
- * socket字符串传输转码
- *
- * @param msg
- * @return
- */
- public static ByteBuf textBytes(String msg) {
- return Unpooled.copiedBuffer((msg + "_split").getBytes());
- }
-
- public static TextWebSocketFrame webSocketBytes(String msg) {
- return new TextWebSocketFrame(msg);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/netty/dispatch/MsgDispatch.java b/src/main/java/com/xcong/excoin/netty/dispatch/MsgDispatch.java
deleted file mode 100644
index 540fd36..0000000
--- a/src/main/java/com/xcong/excoin/netty/dispatch/MsgDispatch.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.xcong.excoin.netty.dispatch;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.netty.bean.RequestBean;
-import com.xcong.excoin.netty.common.NettyTools;
-import com.xcong.excoin.netty.logic.MsgLogic;
-import io.netty.channel.ChannelHandlerContext;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-
-
-/**
- * @author wzy
- * @date 2019-05-08
- */
-@Slf4j
-@Component("msgDispatch")
-public class MsgDispatch implements ApplicationContextAware {
-
- private ApplicationContext applicationContext;
-
- @Autowired
- private MsgLogic msgLogic;
-
- public void webSocketDispatch(ChannelHandlerContext ctx, String msg) {
- RequestBean requestBean = null;
- try {
- requestBean = JSONObject.parseObject(msg, RequestBean.class);
- requestBean.setChannelId(ctx.channel().id().asShortText());
- msgLogic.webSocketMsgLogic(requestBean);
- } catch (Exception e) {
- log.info("#websocket json error:{}#", e);
- ctx.channel().writeAndFlush(NettyTools.webSocketBytes("params error"));
- }
- }
-
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/netty/handler/WebSocketServerHandler.java b/src/main/java/com/xcong/excoin/netty/handler/WebSocketServerHandler.java
deleted file mode 100644
index 3e57246..0000000
--- a/src/main/java/com/xcong/excoin/netty/handler/WebSocketServerHandler.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package com.xcong.excoin.netty.handler;
-
-
-import com.xcong.excoin.netty.common.ChannelManager;
-import com.xcong.excoin.netty.common.Contans;
-import com.xcong.excoin.netty.common.NettyTools;
-import com.xcong.excoin.netty.dispatch.MsgDispatch;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.*;
-import io.netty.handler.codec.http.DefaultFullHttpResponse;
-import io.netty.handler.codec.http.FullHttpRequest;
-import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.codec.http.HttpVersion;
-import io.netty.handler.codec.http.websocketx.*;
-import io.netty.handler.timeout.IdleState;
-import io.netty.handler.timeout.IdleStateEvent;
-import io.netty.util.CharsetUtil;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Date;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
-
-/**
- * @author wzy
- * @email wangdoubleone@gmail.com
- * @date 2019-05-06
- */
-@Slf4j
-@Component
-@ChannelHandler.Sharable
-public class WebSocketServerHandler extends ChannelInboundHandlerAdapter {
-
- private final ConcurrentMap<String, Integer> pingTimes = new ConcurrentHashMap<>();
-
- private static final int MAX_UN_REC_PING_TIMES = 3;
-
- private WebSocketServerHandshaker handshaker;
-
- @Resource(name = "msgDispatch")
- private MsgDispatch msgDispatch;
-
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- log.info("[websocket客户端连入服务器]-->{}", ctx.channel().id());
- ChannelManager.addWebSocketChannel(ctx.channel());
- }
-
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- log.info("[离开websocket服务器]-->{}", ctx.channel().id());
- ChannelManager.removeWebSocketChannel(ctx.channel());
- }
-
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-// LogUtil.info("[websocket服务器收到消息]-->{}, {}", ctx.channel().id(), msg);
- if (msg instanceof FullHttpRequest) {
- // 以http请求形式接入,但是走的是websocket
- handleHttpRequest(ctx, (FullHttpRequest) msg);
- } else if (msg instanceof WebSocketFrame) {
- // 处理websocket客户端的消息
- handlerWebSocketFrame(ctx, (WebSocketFrame) msg);
-
- WebSocketFrame frame = (WebSocketFrame) msg;
- String content;
- try {
- content = ((TextWebSocketFrame) frame).text();
- if (content.contains(Contans.HEART_BEAT)) {
- resetTimes(ctx.channel());
- } else {
- this.msgDispatch.webSocketDispatch(ctx, content);
- }
- } catch (ClassCastException e) {
- content = ((CloseWebSocketFrame) frame).reasonText();
- ctx.writeAndFlush(new TextWebSocketFrame(content));
- }
- }
- }
-
- @Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
- log.info("[触发器触发]");
-// super.userEventTriggered(ctx, evt);
- if (evt instanceof IdleStateEvent) {
- IdleStateEvent event = (IdleStateEvent) evt;
- if (event.state() == IdleState.READER_IDLE) {
-
- } else if (event.state() == IdleState.WRITER_IDLE) {
- /*写超时*/
- ctx.channel().writeAndFlush(NettyTools.webSocketBytes(Contans.HEART_BEAT));
- Integer times = pingTimes.get(ctx.channel().id().asShortText());
- if (times == null) {
- times = 0;
- }
- /*读超时*/
- log.info("===服务端===({}写超时, {})", ctx.channel().id().asShortText(), times);
- // 失败计数器次数大于等于3次的时候,关闭链接,等待client重连
- if (times >= MAX_UN_REC_PING_TIMES) {
- log.info("===服务端===(写超时,关闭chanel)");
- // 连续超过N次未收到client的ping消息,那么关闭该通道,等待client重连
- ctx.channel().close();
- } else {
- // 失败计数器加1
- times++;
- pingTimes.remove(ctx.channel().id().asShortText());
- pingTimes.put(ctx.channel().id().asShortText(), times);
- }
- } else if (event.state() == IdleState.ALL_IDLE) {
- /*总超时*/
- System.out.println("===服务端===(ALL_IDLE 总超时)");
- }
- }
- }
-
- private void resetTimes(Channel channel) {
- pingTimes.remove(channel.id().asShortText());
- pingTimes.put(channel.id().asShortText(), 0);
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- log.error("[websocket服务器发生异常]-->{},{}#", ctx.channel().id(), cause);
- super.exceptionCaught(ctx, cause);
- }
-
-
- private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
- // 判断是否关闭链路的指令
- if (frame instanceof CloseWebSocketFrame) {
- handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
- return;
- }
- // 判断是否ping消息
- if (frame instanceof PingWebSocketFrame) {
- ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
- return;
- }
- // 本例程仅支持文本消息,不支持二进制消息
- if (!(frame instanceof TextWebSocketFrame)) {
- System.out.println("本例程仅支持文本消息,不支持二进制消息");
- throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass().getName()));
- }
- // 返回应答消息
- String request = ((TextWebSocketFrame) frame).text();
- TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString() + ctx.channel().id() + ":" + request);
- // 群发
- // ChannelSupervise.send2All(tws);
- // 返回【谁发的发给谁】
- // ctx.channel().writeAndFlush(tws);
- }
-
- /**
- * 唯一的一次http请求,用于创建websocket
- */
- private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
- InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
- InetAddress inetAddress = inetSocketAddress.getAddress();
- String ip = inetAddress.getHostAddress();
- int port = inetSocketAddress.getPort();
-
- //要求Upgrade为websocket,过滤掉get/Post
- if (!req.decoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) {
- //若不是websocket方式,则创建BAD_REQUEST的req,返回给客户端
- sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
- return;
- }
- WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://" + ip + ":" + port + "/websocket", null, false);
- handshaker = wsFactory.newHandshaker(req);
- if (handshaker == null) {
- WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
- } else {
- handshaker.handshake(ctx.channel(), req);
- }
- }
-
- /**
- * 拒绝不合法的请求,并返回错误信息
- */
- private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, DefaultFullHttpResponse res) {
- // 返回应答给客户端
- if (res.status().code() != 200) {
- ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(),
- CharsetUtil.UTF_8);
- res.content().writeBytes(buf);
- buf.release();
- }
- //服务端向客户端发送数据
- ChannelFuture f = ctx.channel().writeAndFlush(res);
- // 如果是非Keep-Alive,关闭连接
- if (!isKeepAlive(req) || res.status().code() != 200) {
- f.addListener(ChannelFutureListener.CLOSE);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/netty/initalizer/WebSocketServerInitializer.java b/src/main/java/com/xcong/excoin/netty/initalizer/WebSocketServerInitializer.java
deleted file mode 100644
index 54cb224..0000000
--- a/src/main/java/com/xcong/excoin/netty/initalizer/WebSocketServerInitializer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin.netty.initalizer;
-
-import com.xcong.excoin.netty.handler.WebSocketServerHandler;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelPipeline;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import io.netty.handler.codec.http.HttpObjectAggregator;
-import io.netty.handler.codec.http.HttpServerCodec;
-import io.netty.handler.stream.ChunkedWriteHandler;
-import io.netty.handler.timeout.IdleStateHandler;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * @author wzy
- * @email wangdoubleone@gmail.com
- * @date 2019-05-06
- */
-@Component
-public class WebSocketServerInitializer extends ChannelInitializer<NioSocketChannel> {
-
- @Autowired
- private WebSocketServerHandler webSocketServerHandler;
-
- @Override
- protected void initChannel(NioSocketChannel ch) throws Exception {
- ChannelPipeline cp = ch.pipeline();
-
- // http编码器
- cp.addLast(new HttpServerCodec());
- // 聚合器,使用websocket会用到
- cp.addLast(new HttpObjectAggregator(65536));
- cp.addLast(new ChunkedWriteHandler());
- // 心跳
- ch.pipeline().addLast(new IdleStateHandler(0, 10, 0));
- // 自定义业务handler
- cp.addLast(webSocketServerHandler);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/netty/logic/MsgLogic.java b/src/main/java/com/xcong/excoin/netty/logic/MsgLogic.java
deleted file mode 100644
index 2fc8280..0000000
--- a/src/main/java/com/xcong/excoin/netty/logic/MsgLogic.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.xcong.excoin.netty.logic;
-
-
-import com.xcong.excoin.netty.bean.RequestBean;
-
-/**
- * @author wzy
- * @email wangdoubleone@gmail.com
- * @date 2019-05-09
- */
-public interface MsgLogic {
- void webSocketMsgLogic(RequestBean requestBean);
-}
diff --git a/src/main/java/com/xcong/excoin/netty/logic/WebSocketLogic.java b/src/main/java/com/xcong/excoin/netty/logic/WebSocketLogic.java
deleted file mode 100644
index d1c9322..0000000
--- a/src/main/java/com/xcong/excoin/netty/logic/WebSocketLogic.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xcong.excoin.netty.logic;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.netty.bean.RequestBean;
-import com.xcong.excoin.netty.bean.ResponseBean;
-import com.xcong.excoin.netty.common.ChannelManager;
-import com.xcong.excoin.netty.common.NettyTools;
-import io.netty.channel.Channel;
-import org.springframework.stereotype.Component;
-
-
-/**
- * @author wzy
- * @email wangdoubleone@gmail.com
- * @date 2019-05-09
- */
-@Component
-public class WebSocketLogic {
-
-
- public void webReqConnection(RequestBean requestBean) {
- Channel channel = ChannelManager.findWebSocketChannel(requestBean.getChannelId());
- channel.writeAndFlush(NettyTools.webSocketBytes("this is ok"));
- }
-
- public void reqHomeSymbols(RequestBean requestBean) {
- String params = requestBean.getParams();
- JSONObject jsonObject = JSONObject.parseObject(params);
- String token = jsonObject.getString("token");
- String type = jsonObject.getString("type");
- ResponseBean responseBean = ResponseBean.ok(requestBean.getType(), null);
-
- Channel channel = ChannelManager.findWebSocketChannel(requestBean.getChannelId());
- channel.writeAndFlush(NettyTools.webSocketBytes(JSONObject.toJSONString(responseBean)));
- }
-
- public void defaultReq(RequestBean requestBean) {
- Channel channel = ChannelManager.findWebSocketChannel(requestBean.getChannelId());
- channel.writeAndFlush("this is error type");
- }
-}
diff --git a/src/main/java/com/xcong/excoin/netty/logic/impl/MsgLogicImpl.java b/src/main/java/com/xcong/excoin/netty/logic/impl/MsgLogicImpl.java
deleted file mode 100644
index c1fbb4c..0000000
--- a/src/main/java/com/xcong/excoin/netty/logic/impl/MsgLogicImpl.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xcong.excoin.netty.logic.impl;
-
-import com.xcong.excoin.netty.bean.RequestBean;
-import com.xcong.excoin.netty.common.Contans;
-import com.xcong.excoin.netty.logic.MsgLogic;
-import com.xcong.excoin.netty.logic.WebSocketLogic;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-
-/**
- * @author wzy
- * @date 2019-05-09
- */
-@Component
-public class MsgLogicImpl implements MsgLogic {
-
- @Autowired
- private WebSocketLogic webSocketLogic;
-
- @Override
- public void webSocketMsgLogic(RequestBean requestBean) {
- switch (requestBean.getType()) {
- case Contans.WEB_REQ_CONNECTION :
- webSocketLogic.webReqConnection(requestBean);
- break;
- case Contans.HOME_SYMBOLS:
- webSocketLogic.reqHomeSymbols(requestBean);
- default:
- webSocketLogic.defaultReq(requestBean);
- break;
- }
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/netty/server/WebSocketServer.java b/src/main/java/com/xcong/excoin/netty/server/WebSocketServer.java
deleted file mode 100644
index 84b1290..0000000
--- a/src/main/java/com/xcong/excoin/netty/server/WebSocketServer.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.xcong.excoin.netty.server;
-
-import com.xcong.excoin.netty.ChatServer;
-import com.xcong.excoin.netty.initalizer.WebSocketServerInitializer;
-import io.netty.bootstrap.ServerBootstrap;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.nio.NioServerSocketChannel;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * @author wzy
- * @date 2019-05-06
- */
-@Slf4j
-@Component("webSocketServer")
-public class WebSocketServer implements ChatServer {
-
-
- private EventLoopGroup boss = new NioEventLoopGroup();
- private EventLoopGroup work = new NioEventLoopGroup();
-
- private ChannelFuture channelFuture;
-
- @Autowired
- private WebSocketServerInitializer webSocketServerInitializer;
-
- @Override
- public void start() throws Exception {
- log.info("[websocket服务器启动]");
- try {
- ServerBootstrap b = new ServerBootstrap();
- b.group(boss, work)
- .channel(NioServerSocketChannel.class)
- .childHandler(webSocketServerInitializer);
-
- channelFuture = b.bind(9999).sync();
-
- log.info("[websocket服务器启动完成]-->{}", channelFuture.channel().localAddress());
- } finally {
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() {
- shutdown();
- }
- });
- }
- }
-
- @Override
- public void shutdown() {
- if (channelFuture != null) {
- channelFuture.channel().close().syncUninterruptibly();
- }
-
- if (boss != null) {
- boss.shutdownGracefully();
- }
-
- if (work != null) {
- work.shutdownGracefully();
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/quartz/job/BlockCoinUpdateJob.java b/src/main/java/com/xcong/excoin/quartz/job/BlockCoinUpdateJob.java
deleted file mode 100644
index 4138bee..0000000
--- a/src/main/java/com/xcong/excoin/quartz/job/BlockCoinUpdateJob.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.xcong.excoin.quartz.job;
-
-import com.xcong.excoin.modules.coin.service.BlockCoinService;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 链上币种同步任务
- *
- * @author wzy
- * @date 2020-07-02
- **/
-@Component
-@ConditionalOnProperty(prefix = "app", name = "block-job", havingValue = "true")
-public class BlockCoinUpdateJob {
-
- @Resource
- private BlockCoinService blockCoinService;
-
-
- /**
- * ETH_USDT 同步
- */
- @Scheduled(cron = "0 0/10 * * * ? ")
- public void ethUsdtUpdate() {
- blockCoinService.updateEthUsdt();
- }
-
- /**
- * eth 同步
- */
- @Scheduled(cron = "0 1/20 * * * ? ")
- public void ethUpdate() {
- blockCoinService.updateEth();
- }
-
- /**
- * BTC_USDT 同步
- */
- @Scheduled(cron = "0 2/10 * * * ? ")
- public void btcUsdtUpdate() {
- blockCoinService.updateBtcUsdt();
- }
-
- @Scheduled(cron = "0 3/20 * * * ? ")
- public void btcUpdate() {
- blockCoinService.updateBtc();
- }
-
- @Scheduled(cron = "0 4/20 * * * ? ")
- public void eosUpdate() {
- blockCoinService.updateEos();
- }
-
- @Scheduled(cron = "0 6/20 * * * ? ")
- public void xrpUpdate() {
- blockCoinService.updateXrp();
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/quartz/job/DayLineDataUpdateJob.java b/src/main/java/com/xcong/excoin/quartz/job/DayLineDataUpdateJob.java
deleted file mode 100644
index 6d6438c..0000000
--- a/src/main/java/com/xcong/excoin/quartz/job/DayLineDataUpdateJob.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.xcong.excoin.quartz.job;
-
-import com.huobi.client.SubscriptionClient;
-import com.huobi.client.SubscriptionOptions;
-import com.huobi.client.model.Candlestick;
-import com.huobi.client.model.enums.CandlestickInterval;
-import com.xcong.excoin.modules.symbols.service.SymbolsService;
-import com.xcong.excoin.rabbit.pricequeue.WebsocketPriceService;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.Resource;
-
-/**
- * 最新价更新
- *
- * @author wzy
- * @date 2020-05-28
- **/
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "day-line", havingValue = "true")
-public class DayLineDataUpdateJob {
-
- @Resource
- private RedisUtils redisUtils;
-
- @Resource
- private SymbolsService symbolsService;
-
- @Resource
- private WebsocketPriceService websocketPriceService;
-
- @PostConstruct
- public void initNewestPrice() {
- log.info("#=======价格更新开启=======#");
- SubscriptionOptions subscriptionOptions = new SubscriptionOptions();
- subscriptionOptions.setConnectionDelayOnFailure(5);
- subscriptionOptions.setUri("wss://api.hadax.com/ws");
- SubscriptionClient subscriptionClient = SubscriptionClient.create("", "", subscriptionOptions);
-
- subscriptionClient.subscribeCandlestickEvent("btcusdt,ethusdt,eosusdt,etcusdt,ltcusdt,bchusdt,xrpusdt", CandlestickInterval.DAY1, (candlestickEvent) -> {
- Candlestick data = candlestickEvent.getData();
- redisUtils.set(CoinTypeConvert.convert(candlestickEvent.getSymbol()), data);
- });
-
- }
-}
diff --git a/src/main/java/com/xcong/excoin/quartz/job/KlineDataUpdateJob.java b/src/main/java/com/xcong/excoin/quartz/job/KlineDataUpdateJob.java
deleted file mode 100644
index ca41425..0000000
--- a/src/main/java/com/xcong/excoin/quartz/job/KlineDataUpdateJob.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.xcong.excoin.quartz.job;
-
-import com.xcong.excoin.modules.symbols.service.SymbolsService;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * k线数据更新任务
- *
- * @author wzy
- * @date 2020-05-26
- **/
-@Component
-@ConditionalOnProperty(prefix = "app", name = "kline-update-job", havingValue = "true")
-public class KlineDataUpdateJob {
-
- @Resource
- private SymbolsService symbolsService;
-
-
- private static boolean min1 = true;
- private static boolean min5 = true;
- private static boolean min30 = true;
- private static boolean min60 = true;
- private static boolean hour4 = true;
- private static boolean day1 = true;
- private static boolean week = true;
-
-
- /**
- * 定时更新每一分钟的K线数据
- */
- @Scheduled(cron = "0/1 * * * * ? ")
- public void updateSymbolsKineOneMin() {
- if (min1) {
- min1 = false;
- try {
- symbolsService.updateSymbolsKine("1min");
- } catch (Exception e) {
- // e.printStackTrace();
- } finally {
- min1 = true;
- }
- }
- }
-
- /**
- * 定时更新每十分钟的K线数据
- */
- @Scheduled(cron = "0/10 * * * * ? ")
- public void updateSymbolsKineFiveMin() {
- if (min5) {
- min5 = false;
- try {
- symbolsService.updateSymbolsKine("5min");
- } catch (Exception e) {
- //e.printStackTrace();
- } finally {
- min5 = true;
- }
- }
- }
-
- /**
- * 定时更新每30分钟的K线数据
- */
- @Scheduled(cron = "0/120 * * * * ? ")
- public void updateSymbolsKineMin() {
- if (min30) {
- min30 = false;
- try {
- symbolsService.updateSymbolsKine("30min");
- } catch (Exception e) {
- //e.printStackTrace();
- } finally {
- min30 = true;
- }
- }
- }
-
- /**
- * 定时更新1小时的K线数据
- */
- @Scheduled(cron = "* 0/2 * * * ? ")
- public void updateSymbolsKineOneHour() {
- if (min60) {
- min60 = false;
- try {
- symbolsService.updateSymbolsKine("60min");
- } catch (Exception e) {
- //e.printStackTrace();
- } finally {
- min60 = true;
- }
- }
- }
-
- /**
- * 定时更新4小时的K线数据
- */
- @Scheduled(cron = "* 0/1 * * * ? ")
- public void updateSymbolsKineFourHour() {
- if (hour4) {
- hour4 = false;
- try {
- symbolsService.updateSymbolsKine("4hour");
- } catch (Exception e) {
- //e.printStackTrace();
- } finally {
- hour4 = true;
- }
- }
- }
-
-
- /**
- * 定时更新1天的K线数据
- */
- @Scheduled(cron = "* 0/1 * * * ? ")
- public void updateSymbolsKineOneDay() {
- if (day1) {
- day1 = false;
- try {
- symbolsService.updateSymbolsKine("1day");
- } catch (Exception e) {
- //e.printStackTrace();
- } finally {
- day1 = true;
- }
- }
- }
-
- /**
- * 定时更新1周的K线数据
- */
- @Scheduled(cron = "* 0/1 * * * ? ")
- public void updateSymbolsKineOneWeek() {
- if (week) {
- week = false;
- try {
- symbolsService.updateSymbolsKine("1week");
- } catch (Exception e) {
- // e.printStackTrace();
- } finally {
- week = true;
- }
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/quartz/job/LoopExecutorJob.java b/src/main/java/com/xcong/excoin/quartz/job/LoopExecutorJob.java
deleted file mode 100644
index 9fc7240..0000000
--- a/src/main/java/com/xcong/excoin/quartz/job/LoopExecutorJob.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.xcong.excoin.quartz.job;
-
-import com.xcong.excoin.modules.coin.service.OrderCoinService;
-import com.xcong.excoin.modules.contract.service.ContractHoldOrderService;
-import com.xcong.excoin.modules.home.dao.MemberQuickBuySaleDao;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-
-/**
- * @author wzy
- * @date 2020-06-08
- **/
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "loop-job", havingValue = "true")
-public class LoopExecutorJob {
-
- @Resource
- private MemberQuickBuySaleDao memberQuickBuySaleDao;
-
- @Resource
- private ContractHoldOrderService contractHoldOrderService;
-
- @Resource
- private OrderCoinService orderCoinService;
-
- /**
- * 更新快捷充值超时状态
- */
- @Scheduled(cron = "0/5 * * * * ? ")
- @Transactional(rollbackFor = Exception.class)
- public void updateChargeUsdt() {
- try {
- memberQuickBuySaleDao.updateQuickBuySaleTimeOut();
- } catch (Exception e) {
- log.error("更新快捷充值超时状态", e);
- }
- }
-
-
- /**
- * 持仓费计算
- */
- @Scheduled(cron = "0 0 0/8 * * ?")
- public void updateDoingPrice() {
- log.info("#持仓费计算#");
- try {
- contractHoldOrderService.calHoldFeeAmountForBondAmount();
- } catch (Exception e) {
- log.error("#持仓费计算错误#", e);
- }
- }
-
- /**
- * 币币委托单成交
- */
- @Scheduled(cron = "0/5 * * * * ? ")
- public void coinEntrustToDeal() {
- try {
- orderCoinService.dealEntrustCoinOrder();
- } catch (Exception e) {
- log.error("#币币委托单成交错误#", e);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/quartz/job/NewestPriceUpdateJob.java b/src/main/java/com/xcong/excoin/quartz/job/NewestPriceUpdateJob.java
deleted file mode 100644
index 0ac98f7..0000000
--- a/src/main/java/com/xcong/excoin/quartz/job/NewestPriceUpdateJob.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.xcong.excoin.quartz.job;
-
-import com.huobi.client.SubscriptionClient;
-import com.huobi.client.SubscriptionOptions;
-import com.huobi.client.model.Candlestick;
-import com.huobi.client.model.enums.CandlestickInterval;
-import com.xcong.excoin.modules.symbols.service.SymbolsService;
-import com.xcong.excoin.rabbit.pricequeue.WebsocketPriceService;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.Resource;
-
-/**
- * 最新价更新
- *
- * @author wzy
- * @date 2020-05-28
- **/
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "newest-price-update-job", havingValue = "true")
-public class NewestPriceUpdateJob {
-
- @Resource
- private RedisUtils redisUtils;
-
- @Resource
- private SymbolsService symbolsService;
-
- @Resource
- private WebsocketPriceService websocketPriceService;
-
- @PostConstruct
- public void initNewestPrice() {
- log.info("#=======价格更新开启=======#");
- SubscriptionOptions subscriptionOptions = new SubscriptionOptions();
- subscriptionOptions.setConnectionDelayOnFailure(5);
- subscriptionOptions.setUri("wss://api.hadax.com/ws");
- SubscriptionClient subscriptionClient = SubscriptionClient.create("", "", subscriptionOptions);
- subscriptionClient.subscribeTradeEvent("btcusdt,ethusdt,xrpusdt,ltcusdt,bchusdt,eosusdt,etcusdt", tradeEvent -> {
- String symbol = tradeEvent.getSymbol();
- // 根据symbol判断做什么操作
- symbol = CoinTypeConvert.convert(symbol);
- if (null != symbol) {
- String price = tradeEvent.getTradeList().get(0).getPrice().toPlainString();
- // TODO 测试环境关闭这个插入redis
- redisUtils.set(CoinTypeConvert.convertToKey(symbol), price);
- // 比较
- websocketPriceService.comparePriceAsc(symbol, price);
- websocketPriceService.comparePriceDesc(symbol, price);
- //System.out.println("比较完毕:"+symbol+"-"+price);
-
- }
-
- });
-// subscriptionClient.subscribeCandlestickEvent("btcusdt,ethusdt,eosusdt,etcusdt,ltcusdt,bchusdt,xrpusdt", CandlestickInterval.DAY1, (candlestickEvent) -> {
-// Candlestick data = candlestickEvent.getData();
-// redisUtils.set(CoinTypeConvert.convert(candlestickEvent.getSymbol()), data);
-// });
- }
-}
diff --git a/src/main/java/com/xcong/excoin/quartz/job/NotionalPoolingJob.java b/src/main/java/com/xcong/excoin/quartz/job/NotionalPoolingJob.java
deleted file mode 100644
index 75f36ad..0000000
--- a/src/main/java/com/xcong/excoin/quartz/job/NotionalPoolingJob.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.xcong.excoin.quartz.job;
-
-import com.xcong.excoin.modules.blackchain.service.UsdtEthService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import java.util.concurrent.ExecutionException;
-
-/**
- * 归集定时任务
- *
- * @author wzy
- * @date 2020-07-02
- **/
-
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "block-job", havingValue = "true")
-public class NotionalPoolingJob {
-
- @Resource
- private UsdtEthService usdtEthService;
-
- /**
- * usdt 归集
- */
- @Scheduled(cron = "0 5/30 * * * ? ")
- public void poolUsdtEth() {
- try {
- log.info("USDT归集开始");
- usdtEthService.pool();
- log.info("USDT归集结束");
- } catch (ExecutionException | InterruptedException e) {
- log.error("#usdt归集错误#", e);
- }
- }
-
- @Scheduled(cron = "0 2/8 * * * ? ")
- public void usdtEthPoolCheck() {
- log.info("USDTETH归集结果扫描开始");
- usdtEthService.usdtEthPoolCheck();
- }
-
- @Scheduled(cron = "0 2/30 * * * ? ")
- public void poolEth() {
- try {
- usdtEthService.ethPool();
- } catch (ExecutionException | InterruptedException e) {
- log.info("#ETH归集错误#", e);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/quartz/job/UsdtCnyExchangePriceUpdateJob.java b/src/main/java/com/xcong/excoin/quartz/job/UsdtCnyExchangePriceUpdateJob.java
deleted file mode 100644
index 96dc366..0000000
--- a/src/main/java/com/xcong/excoin/quartz/job/UsdtCnyExchangePriceUpdateJob.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.xcong.excoin.quartz.job;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.platform.dao.PlatformCnyUsdtExchangeDao;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.math.BigDecimal;
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-/**
- * 美元-人民币汇率定时任务
- *
- * @author wzy
- * @date 2020-05-28
- **/
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "other-job", havingValue = "true")
-public class UsdtCnyExchangePriceUpdateJob {
-
- @Resource
- private PlatformCnyUsdtExchangeDao cnyUsdtExchangeDao;
-
- @Scheduled(cron = "0 */5 * * * ? ")
- public void updateUsdtCnyExchange() {
- BufferedReader reader = null;
- String result = null;
- StringBuffer sbf = new StringBuffer();
- // 模拟浏览器
- String userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";
- try {
- URL url = new URL("https://otc-api-hk.eiijo.cn/v1/data/config/purchase-price?coinId=2¤cyId=1&matchType=0");
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("GET");
- connection.setReadTimeout(30000);
- connection.setConnectTimeout(30000);
- connection.setRequestProperty("User-agent", userAgent);
- connection.connect();
- InputStream is = connection.getInputStream();
- reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
- String strRead = null;
- while ((strRead = reader.readLine()) != null) {
- sbf.append(strRead);
- sbf.append("\r\n");
- }
- reader.close();
- result = sbf.toString();
-
- JSONObject jsonObject = (JSONObject) JSONObject.parse(result);
- String code = jsonObject.getString("code");
- if ("200".equals(code)) {
- JSONObject jsonData = (JSONObject) jsonObject.get("data");
- cnyUsdtExchangeDao.updateUsdt(BigDecimal.valueOf(jsonData.getDouble("price")));
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/consumer/OperateOrderPriceConsumer.java b/src/main/java/com/xcong/excoin/rabbit/consumer/OperateOrderPriceConsumer.java
deleted file mode 100644
index 45ff0f7..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/consumer/OperateOrderPriceConsumer.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.rabbit.consumer;
-
-import com.alibaba.fastjson.JSONObject;
-import com.rabbitmq.client.Channel;
-import com.xcong.excoin.configurations.RabbitMqConfig;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import com.xcong.excoin.rabbit.pricequeue.OrderOperatePriceService;
-import org.springframework.amqp.core.Message;
-import org.springframework.amqp.rabbit.annotation.RabbitListener;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-
-
-/**
- * 用户修改止损止盈价格、提价限价委托、下单爆仓价等消息
- * 后台打包开启 APP 不开启
- * @author helius
- */
-@Component
-@ConditionalOnProperty(prefix = "app", name = "newest-price-update-job", havingValue = "true")
-public class OperateOrderPriceConsumer {
-
-
- /**
- * 用户修改止损止盈价格、提价限价委托、下单爆仓价等消息
- *
- * @param message 消息体
- * @param channel 信道
- * @date 2019年4月19日
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_PRICEOPERATE)
- public void onMessageMorePro(Message message, Channel channel) {
- String content = new String(message.getBody());
- System.out.println("我收到了用户的订单操作消息:" + content);
- // 操作前的map
- // 转为model
- OrderModel orderModel = JSONObject.parseObject(content, OrderModel.class);
- // 向优先队列添加
- OrderOperatePriceService.dealWithNewMq(orderModel);
-
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/consumer/TestConsumer.java b/src/main/java/com/xcong/excoin/rabbit/consumer/TestConsumer.java
deleted file mode 100644
index aea3c07..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/consumer/TestConsumer.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.rabbit.consumer;
-
-import com.xcong.excoin.configurations.RabbitMqConfig;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.amqp.rabbit.annotation.RabbitListener;
-import org.springframework.stereotype.Component;
-
-/**
- * @author wzy
- * @date 2020-05-25
- **/
-@Slf4j
-@Component
-public class TestConsumer {
-
-
- @RabbitListener(queues = RabbitMqConfig.QUEUE_TEST)
- public void doSomething(String content) {
- log.info("#---->{}#", content);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/consumer/WebsocketPriceConsumer.java b/src/main/java/com/xcong/excoin/rabbit/consumer/WebsocketPriceConsumer.java
deleted file mode 100644
index b959b0e..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/consumer/WebsocketPriceConsumer.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.xcong.excoin.rabbit.consumer;
-
-import com.alibaba.fastjson.JSONArray;
-import com.rabbitmq.client.Channel;
-import com.xcong.excoin.configurations.RabbitMqConfig;
-import com.xcong.excoin.modules.contract.service.RabbitOrderService;
-import com.xcong.excoin.modules.contract.service.impl.OrderWebsocketServiceImpl;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.amqp.core.Message;
-import org.springframework.amqp.rabbit.annotation.RabbitListener;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import java.util.List;
-
-
-/**
- * APP和后台打包都开启
- *
- * @author helius
- */
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "rabbit-consumer", havingValue = "true")
-public class WebsocketPriceConsumer {
-
- @Resource
- OrderWebsocketServiceImpl orderWebsocketService;
-
- @Resource
- RabbitOrderService orderService;
-
-
- /**
- * 开多止盈
- *
- * @param message 消息体
- * @param channel 信道
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_MOREPRO)
- public void onMessageMorePro(Message message, Channel channel) {
- String content = new String(message.getBody());
- log.info("==message-price-consumer==我收到消息了开多止盈 : {}", content);
- List<OrderModel> list = JSONArray.parseArray(content, OrderModel.class);
- // 开始处理
- orderWebsocketService.dealOrderFromMq(list, 9);
- }
- // 1:买入委托2:开多3:开空4:平多5:平空6:爆仓平多7:爆仓平空8:撤单9:止盈平多10:止盈平空11:止损平多12:止损平空
-
- /**
- * 开空止盈
- *
- * @param message
- * @param channel
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_LESSPRO)
- public void onMessageLessPro(Message message, Channel channel) {
- String content = new String(message.getBody());
- log.info("==message-price-consumer==我收到消息了开空止盈 : {}", content);
- // 开始处理
- List<OrderModel> list = JSONArray.parseArray(content, OrderModel.class);
- // 开始处理
- orderWebsocketService.dealOrderFromMq(list, 10);
- }
-
-
- /**
- * 开多止损
- *
- * @param message
- * @param channel
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_MORELOSS)
- public void onMessageMoreLoss(Message message, Channel channel) {
- String content = new String(message.getBody());
- log.info("==message-price-consumer==我收到消息了开多止损 : {}", content);
- // 开始处理
- List<OrderModel> list = JSONArray.parseArray(content, OrderModel.class);
- // 开始处理
- orderWebsocketService.dealOrderFromMq(list, 11);
- }
-
- /**
- * 开空止损
- *
- * @param message
- * @param channel
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_LESSLOSS)
- public void onMessageLessLoss(Message message, Channel channel) {
- String content = new String(message.getBody());
- log.info("==message-price-consumer==我收到消息了开空止损 : {}", content);
- // 开始处理
- List<OrderModel> list = JSONArray.parseArray(content, OrderModel.class);
- // 开始处理
- orderWebsocketService.dealOrderFromMq(list, 12);
- }
-
- /**
- * 限价委托
- *
- * @param message
- * @param channel
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_LIMIT)
- public void onMessageLimit(Message message, Channel channel) {
- String content = new String(message.getBody());
- log.info("==message-price-consumer==我收到消息了限价委托 : {}", content);
- // 开始处理
- List<OrderModel> list = JSONArray.parseArray(content, OrderModel.class);
- // 开始处理
- orderWebsocketService.dealForLimitMq(list);
- }
-
- /**
- * 爆仓消费者
- *
- * @param message
- * @param channel
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_COINOUT)
- public void onMessageCoinout(Message message, Channel channel) {
- String content = new String(message.getBody());
- log.info("==message-price-consumer==我收到消息了爆仓 : {}", content);
- // 开始处理
- List<OrderModel> list = JSONArray.parseArray(content, OrderModel.class);
- // 开始处理
- orderWebsocketService.dealOrderFromMq(list, 6);
- }
-
- /**
- * 平仓
- *
- * @param message
- * @param channel
- */
- @RabbitListener(queues = RabbitMqConfig.QUEUE_CLOSETRADE)
- public void onMessageCloseTrade(Message message, Channel channel) {
- String content = new String(message.getBody());
- log.info("==message-price-consumer==我收到消息了平仓: {}", content);
- // 订单
- List<Long> ids = JSONArray.parseArray(content, Long.class);
- orderService.cancelHoldOrder(ids);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/init/OrderProducerInit.java b/src/main/java/com/xcong/excoin/rabbit/init/OrderProducerInit.java
deleted file mode 100644
index 25638d8..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/init/OrderProducerInit.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.xcong.excoin.rabbit.init;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.common.enumerates.RabbitPriceTypeEnum;
-import com.xcong.excoin.modules.contract.dao.ContractEntrustOrderDao;
-import com.xcong.excoin.modules.contract.dao.ContractHoldOrderDao;
-import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.rabbit.pricequeue.OrderModel;
-import com.xcong.excoin.rabbit.producer.OrderProducer;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.List;
-
-/**
- * 后台开启 APP不开启
- *
- * @author helius
- */
-@Slf4j
-@Component
-@ConditionalOnProperty(prefix = "app", name = "newest-price-update-job", havingValue = "true")
-public class OrderProducerInit {
-
- @Resource
- private ContractEntrustOrderDao contractEntrustOrderDao;
-
- @Resource
- private ContractHoldOrderDao contractHoldOrderDao;
-
- @Resource
- private OrderProducer producer;
-
- @PostConstruct
- public void initOrder() {
- log.info("=======初始化未完成订单信息=======");
-
- // 查询所有未平仓的单
- List<ContractHoldOrderEntity> holdOrderEntities = contractHoldOrderDao.selectAllHoldOrder();
- // 查询所有未完成的委托单
- List<ContractEntrustOrderEntity> entrustOrderEntities = contractEntrustOrderDao.selectAllEntrustOrder();
-
- if (CollectionUtils.isNotEmpty(holdOrderEntities)) {
- for (ContractHoldOrderEntity order : holdOrderEntities) {
- // 开多1,开空 2
- int openingType = order.getOpeningType();
- // 1:买入委托2:开多3:开空4:平多5:平空6:爆仓平多7:爆仓平空
- // 9:止盈平多10:止盈平空11:止损平多12:止损平空
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == openingType) {
- // 开多 发送开多止损 止盈 爆仓
- // 爆仓价
- BigDecimal forceSetPrice = order.getForceClosingPrice();
- if (forceSetPrice != null) {
- OrderModel model = new OrderModel(order.getId(), RabbitPriceTypeEnum.CLOSE_MORE_BOMB.getValue(), forceSetPrice.toPlainString(),
- order.getSymbol(), order.getOperateNo());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- // 止损
- BigDecimal stopLossPrice = order.getStopLossPrice();
- if (stopLossPrice != null && stopLossPrice.compareTo(BigDecimal.ZERO) > 0) {
- OrderModel model = new OrderModel(order.getId(), RabbitPriceTypeEnum.CLOSE_MORE_STOP_LESS.getValue(),
- stopLossPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(),
- order.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- // 止盈
- BigDecimal stopProfitPrice = order.getStopProfitPrice();
- if (stopProfitPrice != null && stopProfitPrice.compareTo(BigDecimal.ZERO) > 0) {
- OrderModel model = new OrderModel(order.getId(), RabbitPriceTypeEnum.CLOSE_MORE_STOP_PROFIT.getValue(),
- stopProfitPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(),
- order.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
-
- } else {
- // 开空 发送开空止损 止盈 爆仓
- // 爆仓价
- BigDecimal forceSetPrice = order.getForceClosingPrice();
- if (forceSetPrice != null) {
- OrderModel model = new OrderModel(order.getId(), RabbitPriceTypeEnum.CLOSE_LESS_BOMB.getValue(), forceSetPrice.toPlainString(),
- order.getSymbol(), order.getOperateNo());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- // 止损
- BigDecimal stopLossPrice = order.getStopLossPrice();
- if (stopLossPrice != null && stopLossPrice.compareTo(BigDecimal.ZERO) > 0) {
- OrderModel model = new OrderModel(order.getId(), RabbitPriceTypeEnum.CLOSE_LESS_STOP_LESS.getValue(),
- stopLossPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(),
- order.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- // 止盈
- BigDecimal stopProfitPrice = order.getStopProfitPrice();
- if (stopProfitPrice != null && stopProfitPrice.compareTo(BigDecimal.ZERO) > 0) {
- OrderModel model = new OrderModel(order.getId(), RabbitPriceTypeEnum.CLOSE_LESS_STOP_PROFIT.getValue(),
- stopProfitPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(),
- order.getSymbol());
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- }
-
- }
- }
-
- if (CollectionUtils.isNotEmpty(entrustOrderEntities)) {
- for (ContractEntrustOrderEntity order : entrustOrderEntities) {
- // 开多1,开空 2
- int entrustType = order.getEntrustType();
- // 开多
- BigDecimal entrustPrice = order.getEntrustPrice();
- OrderModel model;
- if (ContractEntrustOrderEntity.ENTRUST_TYPE_OPEN_MORE == entrustType) {
- // 开多委托
- model = new OrderModel(order.getId(), RabbitPriceTypeEnum.ENTRUST_OPEN_MORE.getValue(),
- entrustPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(),
- order.getSymbol());
-
- } else {
- model = new OrderModel(order.getId(), RabbitPriceTypeEnum.ENTRUST_OPEN_LESS.getValue(),
- entrustPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(),
- order.getSymbol());
- }
- producer.sendPriceOperate(JSONObject.toJSONString(model));
- }
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/pricequeue/AscBigDecimal.java b/src/main/java/com/xcong/excoin/rabbit/pricequeue/AscBigDecimal.java
deleted file mode 100644
index 73762bf..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/pricequeue/AscBigDecimal.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.xcong.excoin.rabbit.pricequeue;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
-/**
- * 正序的 从小到大 头元素最小
- */
-public class AscBigDecimal implements Comparable{
-
- private BigDecimal value;
-
- public AscBigDecimal(String val) {
- this.value = new BigDecimal(val).setScale(8, RoundingMode.HALF_UP);
- }
-
- public AscBigDecimal(double val){
- this.value = new BigDecimal(val).setScale(8, RoundingMode.HALF_UP);
- }
-
- public BigDecimal getValue() {
- return value;
- }
-
- public void setValue(BigDecimal value) {
- this.value = value;
- }
-
- @Override
- public int compareTo(Object o) {
- if(o==null){
- return -1;
- }
- AscBigDecimal val = (AscBigDecimal)o;
- if(this.value.compareTo(val.getValue())>0){
- return 1;
- }else if(this.value.compareTo(val.getValue())<0){
- return -1;
- }else {
- return 0;
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/pricequeue/DescBigDecimal.java b/src/main/java/com/xcong/excoin/rabbit/pricequeue/DescBigDecimal.java
deleted file mode 100644
index 3ed88f0..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/pricequeue/DescBigDecimal.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.xcong.excoin.rabbit.pricequeue;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
-/**
- * 倒叙序的 从大到小 头元素最大
- */
-public class DescBigDecimal implements Comparable{
-
-
- private BigDecimal value;
-
- public DescBigDecimal(String val) {
- this.value = new BigDecimal(val).setScale(8, RoundingMode.HALF_UP);
- }
-
- public DescBigDecimal(double val){
- this.value = new BigDecimal(val).setScale(8, RoundingMode.HALF_UP);
- }
-
- public BigDecimal getValue() {
- return value;
- }
-
- public void setValue(BigDecimal value) {
- this.value = value;
- }
-
- @Override
- public int compareTo(Object o) {
- if(o==null){
- return -1;
- }
- DescBigDecimal val = (DescBigDecimal)o;
- if(this.value.compareTo(val.getValue())>0){
- return -1;
- }else if(this.value.compareTo(val.getValue())<0){
- return 1;
- }else {
- return 0;
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/pricequeue/OrderModel.java b/src/main/java/com/xcong/excoin/rabbit/pricequeue/OrderModel.java
deleted file mode 100644
index abc7c7c..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/pricequeue/OrderModel.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.xcong.excoin.rabbit.pricequeue;
-
-public class OrderModel {
- /**
- * 订单ID
- */
- private Long orderId;
- /**
- * 类型
- */
- private Integer type;
-
- /**
- * 触发价格
- */
- private String price;
-
- /**
- * 币种
- */
- private String symbol;
-
- /**
- * 爆仓价位设置次数
- */
- private Integer operateNo;
-
-
- public OrderModel(Long orderId, Integer type, String price, String symbol){
- this.orderId= orderId;
- this.type= type;
- this.price= price;
- this.symbol= symbol;
- }
-
- public OrderModel(Long orderId,Integer type,String price, String symbol,Integer operateNo){
- this.orderId= orderId;
- this.type= type;
- this.price= price;
- this.symbol= symbol;
- this.operateNo= operateNo;
- }
-
- public Integer getOperateNo() {
- return operateNo;
- }
-
- public void setOperateNo(Integer operateNo) {
- this.operateNo = operateNo;
- }
-
- public Long getOrderId() {
- return orderId;
- }
-
- public void setOrderId(Long orderId) {
- this.orderId = orderId;
- }
-
- public Integer getType() {
- return type;
- }
-
- public void setType(Integer type) {
- this.type = type;
- }
-
- public String getPrice() {
- return price;
- }
-
- public void setPrice(String price) {
- this.price = price;
- }
-
- public String getSymbol() {
- return symbol;
- }
-
- public void setSymbol(String symbol) {
- this.symbol = symbol;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/pricequeue/OrderOperatePriceService.java b/src/main/java/com/xcong/excoin/rabbit/pricequeue/OrderOperatePriceService.java
deleted file mode 100644
index d936325..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/pricequeue/OrderOperatePriceService.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.xcong.excoin.rabbit.pricequeue;
-
-import com.alibaba.fastjson.JSONObject;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 处理消费者的订单止盈等价格信息
- */
-@Slf4j
-public class OrderOperatePriceService {
-
- /**
- * 处理用户提交的止盈止损价格 爆仓 限价委托
- *
- * @param orderModel
- */
- public static void dealWithNewMq(OrderModel orderModel) {
- // 根据不同的类型将价格信息加入到对应队列和MAP
- // 【1:买入委托2:开多3:开空4:平多5:平空6:爆仓平多7:爆仓平空8:撤单9:止盈平多10:止盈平空11:止损平多12:止损平空】
- int type = orderModel.getType();
- Map<String, List<OrderModel>> orderMap = PricePriorityQueue.getOrderMap(orderModel.getSymbol(), type);
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- // 需要价格涨的
- PriorityBlockingQueue<AscBigDecimal> queue = PricePriorityQueue.getQueueAsc(orderModel.getSymbol());
- dealPriceAsc(orderModel, orderMap, queue);
- } else {
- // 需要价格跌的
- PriorityBlockingQueue<DescBigDecimal> queue = PricePriorityQueue.getQueueDesc(orderModel.getSymbol());
- dealPriceDesc(orderModel, orderMap, queue);
- }
-
- }
-
- /**
- * 倒叙的添加价格和订单
- *
- * @param orderMap
- * @param queue
- */
- public static void dealPriceDesc(OrderModel order, Map<String, List<OrderModel>> orderMap, PriorityBlockingQueue<DescBigDecimal> queue) {
- // 添加币种的价格和价格订单信息
- String price = order.getPrice();
- int type = order.getType();
- Long orderId = order.getOrderId();
- queue.add(new DescBigDecimal(price));
-
- log.info("原有:{}", JSONObject.toJSONString(orderMap));
- removeExistOrder(type, orderId, orderMap);
- log.info("删除后:{}", JSONObject.toJSONString(orderMap));
- if (orderMap.containsKey(price)) {
- // 有这个价的key
- List<OrderModel> list = orderMap.get(price);
- // 判断这个单的这个类型是否有
-// if (CollectionUtils.isNotEmpty(list)) {
- // 新增
- OrderModel orderModel = new OrderModel(orderId, type, price, null,order.getOperateNo());
- list.add(orderModel);
-// }
- } else {
- List<OrderModel> list = new ArrayList<OrderModel>();
- OrderModel orderModel = new OrderModel(orderId, type, price, null,order.getOperateNo());
- list.add(orderModel);
- orderMap.put(price, list);
- }
- log.info("调整后:{}", JSONObject.toJSONString(orderMap));
- }
-
-
- /**
- * 正序的添加价格和订单
- *
- * @param orderMap
- * @param queue
- */
- public static void dealPriceAsc(OrderModel order, Map<String, List<OrderModel>> orderMap, PriorityBlockingQueue<AscBigDecimal> queue) {
- // 添加币种的价格和价格订单信息
- String price = order.getPrice();
- int type = order.getType();
- Long orderId = order.getOrderId();
- queue.add(new AscBigDecimal(price));
- log.info("原有:{}", JSONObject.toJSONString(orderMap));
- // 需要找到这个订单的原始的单进行处理
- removeExistOrder(type, orderId, orderMap);
- log.info("删除后:{}", JSONObject.toJSONString(orderMap));
- if (orderMap.containsKey(price)) {
- // 有这个价的key
- List<OrderModel> list = orderMap.get(price);
- // 判断这个单的这个类型是否有
-// if (CollectionUtils.isNotEmpty(list)) {
- // 新增
- OrderModel orderModel = new OrderModel(orderId, type, price, null,order.getOperateNo());
- list.add(orderModel);
-// }
- } else {
- List<OrderModel> list = new ArrayList<OrderModel>();
- OrderModel orderModel = new OrderModel(orderId, type, price, null,order.getOperateNo());
- list.add(orderModel);
- orderMap.put(price, list);
- }
- log.info("调整后:{}", JSONObject.toJSONString(orderMap));
- }
-
- private static void removeExistOrder(Integer type, Long orderId, Map<String, List<OrderModel>> orderMap) {
- // 需要找到这个订单的原始的单进行处理
- boolean breakFlag = false;
- for (Map.Entry<String, List<OrderModel>> entry : orderMap.entrySet()) {
- List<OrderModel> value = entry.getValue();
- if (CollectionUtils.isNotEmpty(value)) {
- Iterator<OrderModel> iterator = value.iterator();
- if (iterator.hasNext()) {
- OrderModel next = iterator.next();
- if (next.getType().equals(type) && orderId.equals(next.getOrderId())) {
- // 移除这个
- System.out.println("存在相同的平仓类型,删除原来的:"+next.getOrderId()+",价格:"+next.getPrice());
- iterator.remove();
- break;
-
- }
- }
-
- }
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/pricequeue/PricePriorityQueue.java b/src/main/java/com/xcong/excoin/rabbit/pricequeue/PricePriorityQueue.java
deleted file mode 100644
index 36cbffa..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/pricequeue/PricePriorityQueue.java
+++ /dev/null
@@ -1,300 +0,0 @@
-package com.xcong.excoin.rabbit.pricequeue;
-
-
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.PriorityBlockingQueue;
-
-/**
- * 止盈止损的价格队列
- */
-public class PricePriorityQueue {
-
- /**
- * BTC 正序队列 头元素最小 开多止损 开空止盈 开多爆仓 限价开多
- */
- public static PriorityBlockingQueue<AscBigDecimal> BTC_QUEUE_ASC = null;
-
- private static Map<String, List<OrderModel>> BTC_MAP_ASC = null;
-
- /**
- * BTC 倒序队列 头元素最大 开多止盈 开空止损 开空爆仓 限价开空
- */
- public static PriorityBlockingQueue<DescBigDecimal> BTC_QUEUE_DESC = null;
-
- private static Map<String, List<OrderModel>> BTC_MAP_DESC = null;
- /**
- * ETH 正序队列 头元素最小 开多止损 开空止盈 开多爆仓 限价开多
- */
- private static PriorityBlockingQueue<AscBigDecimal> ETH_QUEUE_ASC = null;
-
- private static Map<String, List<OrderModel>> ETH_MAP_ASC = null;
-
- /**
- * ETH 倒序队列 头元素最大 开多止盈 开空止损 开空爆仓 限价开空
- */
- private static PriorityBlockingQueue<DescBigDecimal> ETH_QUEUE_DESC = null;
-
- private static Map<String, List<OrderModel>> ETH_MAP_DESC = null;
-
- /**
- * XRP 正序队列 头元素最小 开多止损 开空止盈 开多爆仓 限价开多
- */
- private static PriorityBlockingQueue<AscBigDecimal> XRP_QUEUE_ASC = null;
-
- private static Map<String, List<OrderModel>> XRP_MAP_ASC = null;
-
- /**
- * XRP 倒序队列 头元素最大 开多止盈 开空止损 开空爆仓 限价开空
- */
- private static PriorityBlockingQueue<DescBigDecimal> XRP_QUEUE_DESC = null;
- private static Map<String, List<OrderModel>> XRP_MAP_DESC = null;
-
- /**
- * LTC 正序队列 头元素最小 开多止损 开空止盈 开多爆仓 限价开多
- */
- private static PriorityBlockingQueue<AscBigDecimal> LTC_QUEUE_ASC = null;
-
- private static Map<String, List<OrderModel>> LTC_MAP_ASC = null;
-
- /**
- * LTC 倒序队列 头元素最大 开多止盈 开空止损 开空爆仓 限价开空
- */
- private static PriorityBlockingQueue<DescBigDecimal> LTC_QUEUE_DESC = null;
-
- private static Map<String, List<OrderModel>> LTC_MAP_DESC = null;
-
- /**
- * BCH 正序队列 头元素最小 开多止损 开空止盈 开多爆仓 限价开多
- */
- private static PriorityBlockingQueue<AscBigDecimal> BCH_QUEUE_ASC = null;
-
- private static Map<String, List<OrderModel>> BCH_MAP_ASC = null;
-
- /**
- * BCH 倒序队列 头元素最大 开多止盈 开空止损 开空爆仓 限价开空
- */
- private static PriorityBlockingQueue<DescBigDecimal> BCH_QUEUE_DESC = null;
-
- private static Map<String, List<OrderModel>> BCH_MAP_DESC = null;
-
- /**
- * EOS 正序队列 头元素最小 开多止损 开空止盈 开多爆仓 限价开多
- */
- private static PriorityBlockingQueue<AscBigDecimal> EOS_QUEUE_ASC = null;
-
- private static Map<String, List<OrderModel>> EOS_MAP_ASC = null;
-
- /**
- * EOS 倒序队列 头元素最大 开多止盈 开空止损 开空爆仓 限价开空
- */
- private static PriorityBlockingQueue<DescBigDecimal> EOS_QUEUE_DESC = null;
-
- private static Map<String, List<OrderModel>> EOS_MAP_DESC = null;
-
- /**
- * ETC 正序队列 头元素最小 开多止损 开空止盈 开多爆仓 限价开多
- */
- private static PriorityBlockingQueue<AscBigDecimal> ETC_QUEUE_ASC = null;
-
- private static Map<String, List<OrderModel>> ETC_MAP_ASC = null;
-
- /**
- * ETC 倒序队列 头元素最大 开多止盈 开空止损 开空爆仓 限价开空
- */
- private static PriorityBlockingQueue<DescBigDecimal> ETC_QUEUE_DESC = null;
-
- private static Map<String, List<OrderModel>> ETC_MAP_DESC = null;
-
-
- // 收到消息队列的方法 即收取到新的止盈止损等
- // 【1:买入委托2:开多3:开空4:平多5:平空6:爆仓平多7:爆仓平空8:撤单9:止盈平多10:止盈平空11:止损平多12:止损平空】
- public static PriorityBlockingQueue<AscBigDecimal> getQueueAsc(String symbol) {
- switch (symbol) {
- case "BTC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (BTC_QUEUE_ASC == null) {
- BTC_QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
-
- return BTC_QUEUE_ASC;
- case "ETH/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (ETH_QUEUE_ASC == null) {
- ETH_QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return ETH_QUEUE_ASC;
- case "XRP/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (XRP_QUEUE_ASC == null) {
- XRP_QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return XRP_QUEUE_ASC;
- case "LTC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (LTC_QUEUE_ASC == null) {
- LTC_QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return LTC_QUEUE_ASC;
- case "BCH/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (BCH_QUEUE_ASC == null) {
- BCH_QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return BCH_QUEUE_ASC;
- case "EOS/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (EOS_QUEUE_ASC == null) {
- EOS_QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return EOS_QUEUE_ASC;
- case "ETC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (ETC_QUEUE_ASC == null) {
- ETC_QUEUE_ASC = new PriorityBlockingQueue<AscBigDecimal>();
- }
- return ETC_QUEUE_ASC;
- default:
- break;
- }
- return null;
- }
-
- public static PriorityBlockingQueue<DescBigDecimal> getQueueDesc(String symbol) {
- switch (symbol) {
- case "BTC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- //if (type == 11 || type == 10 || type == 7 || type == 6 || type == 2) {
- if (BTC_QUEUE_DESC == null) {
- BTC_QUEUE_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return BTC_QUEUE_DESC;
- case "ETH/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (ETH_QUEUE_DESC == null) {
- ETH_QUEUE_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return ETH_QUEUE_DESC;
- case "XRP/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (XRP_QUEUE_DESC == null) {
- XRP_QUEUE_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return XRP_QUEUE_DESC;
- case "LTC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (LTC_QUEUE_DESC == null) {
- LTC_QUEUE_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return LTC_QUEUE_DESC;
- case "BCH/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (BCH_QUEUE_DESC == null) {
- BCH_QUEUE_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return BCH_QUEUE_DESC;
- case "EOS/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (EOS_QUEUE_DESC == null) {
- EOS_QUEUE_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return EOS_QUEUE_DESC;
- case "ETC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (ETC_QUEUE_DESC == null) {
- ETC_QUEUE_DESC = new PriorityBlockingQueue<DescBigDecimal>();
- }
- return ETC_QUEUE_DESC;
- default:
- break;
- }
- return null;
- }
-
- /**
- * 获得币种价格订单map
- * @param symbol
- * @param type
- * @return
- */
- public static Map<String,List<OrderModel>> getOrderMap(String symbol, int type) {
- switch (symbol) {
- case "BTC/USDT": // 开空止损 开多止盈 开空爆仓 限价开空
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- if (BTC_MAP_ASC == null) {
- BTC_MAP_ASC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return BTC_MAP_ASC;
- } else {
- if (BTC_MAP_DESC == null) {
- BTC_MAP_DESC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return BTC_MAP_DESC;
- }
- case "ETH/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- if (ETH_MAP_ASC == null) {
- ETH_MAP_ASC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return ETH_MAP_ASC;
- } else {
- if (ETH_MAP_DESC == null) {
- ETH_MAP_DESC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return ETH_MAP_DESC;
- }
- case "XRP/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- if (XRP_MAP_ASC == null) {
- XRP_MAP_ASC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return XRP_MAP_ASC;
- } else {
- if (XRP_MAP_DESC == null) {
- XRP_MAP_DESC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return XRP_MAP_DESC;
- }
- case "LTC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- if (LTC_MAP_ASC == null) {
- LTC_MAP_ASC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return LTC_MAP_ASC;
- } else {
- if (LTC_MAP_DESC == null) {
- LTC_MAP_DESC =new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return LTC_MAP_DESC;
- }
- case "BCH/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- if (BCH_MAP_ASC == null) {
- BCH_MAP_ASC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return BCH_MAP_ASC;
- } else {
- if (BCH_MAP_DESC == null) {
- BCH_MAP_DESC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return BCH_MAP_DESC;
- }
- case "EOS/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- if (EOS_MAP_ASC == null) {
- EOS_MAP_ASC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return EOS_MAP_ASC;
- } else {
- if (EOS_MAP_DESC == null) {
- EOS_MAP_DESC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return EOS_MAP_DESC;
- }
- case "ETC/USDT": // 开多止损 开空止盈 开多爆仓 限价开多
- if (type == 12 || type == 9 || type == 7 || type == 3) {
- if (ETC_MAP_ASC == null) {
- ETC_MAP_ASC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return ETC_MAP_ASC;
- } else {
- if (ETC_MAP_DESC == null) {
- ETC_MAP_DESC = new ConcurrentHashMap<String,List<OrderModel>>();
- }
- return ETC_MAP_DESC;
- }
- default:
- break;
- }
- return null;
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/pricequeue/WebsocketPriceService.java b/src/main/java/com/xcong/excoin/rabbit/pricequeue/WebsocketPriceService.java
deleted file mode 100644
index af91983..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/pricequeue/WebsocketPriceService.java
+++ /dev/null
@@ -1,224 +0,0 @@
-package com.xcong.excoin.rabbit.pricequeue;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.rabbit.producer.OrderProducer;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.PriorityBlockingQueue;
-
-@Slf4j
-@Component
-public class WebsocketPriceService {
-
- @Autowired
- OrderProducer orderProducer;
-
- /**
- * @param symbol
- * @param price
- */
- public void comparePriceAsc(String symbol, String price) {
- // 比较价格 正序的 最小元素在头部 开多止盈 开空止损等
- PriorityBlockingQueue<AscBigDecimal> queue = PricePriorityQueue.getQueueAsc(symbol);
- // 最小的
- AscBigDecimal b = queue.peek();
- // 当前价
- AscBigDecimal now = new AscBigDecimal(price);
- List<AscBigDecimal> list = new ArrayList<AscBigDecimal>();
- // 找到所有比当前价格大的 是需要操作的
- if (b != null && b.compareTo(now) <= 0) {
- // 可以操作
- System.out.println("当前价格:" + price + "---正序---" + "队列价格:" + b.getValue().toPlainString() + " time:" + new Date());
- while (queue.peek() != null && queue.peek().compareTo(now) <= 0) {
- // 可以发送消息操作
- list.add(queue.remove());
- }
- }
-
- if (CollectionUtils.isNotEmpty(list)) {
- dealAscPriceOrderAndSenMq(list, symbol);
- }
-
- }
-
- public void comparePriceDesc(String symbol, String price) {
- // 比较价格 倒叙的 开多止损 开空止盈
- PriorityBlockingQueue<DescBigDecimal> queue = PricePriorityQueue.getQueueDesc(symbol);
- // 最大价格
- DescBigDecimal b = queue.peek();
- // 当前价格
- DescBigDecimal now = new DescBigDecimal(price);
- List<DescBigDecimal> list = new ArrayList<DescBigDecimal>();
- // 找到比当前价格还大的就是需要操作的 开多止损
- // 即最大的币当前价大 那么需要开多止损
- if (b != null && b.compareTo(now) <= 0) {
- // 可以操作
- System.out.println("当前价格:" + price + "---倒序操作---" + "队列:" + b.getValue().toPlainString() + " time:" + new Date());
-
- while (queue.peek() != null && queue.peek().compareTo(now) <= 0) {
- // 可以发送消息操作
- list.add(queue.remove());
- log.info("#{}#", JSONObject.toJSONString(list));
- }
- }
- if (CollectionUtils.isNotEmpty(list)) {
- dealDescPriceOrderAndSenMq(list, symbol);
- }
-
- }
-
- // 处理消息 正序的 包括
- // 1:买入委托2:开多3:开空4:平多5:平空6:爆仓平多7:爆仓平空8:撤单9:止盈平多10:止盈平空11:止损平多12:止损平空
- public void dealAscPriceOrderAndSenMq(List<AscBigDecimal> list, String symbol) {
- if (CollectionUtils.isNotEmpty(list)) {
- // 根据不同类型发送不同消息 1 倒序 2 正序
- List<OrderModel> orderModelList = new ArrayList<OrderModel>();
- // 3 正序
- Map<String, List<OrderModel>> orderMap = PricePriorityQueue.getOrderMap(symbol, 3);
- // 根据价格查询到对应的订单
- for (AscBigDecimal asc : list) {
- String key = asc.getValue().toPlainString();
- assert orderMap != null;
- log.info("----->->{}, --> {}", JSONObject.toJSONString(orderMap), key);
- if (orderMap.containsKey(key)) {
- orderModelList.addAll(orderMap.get(key));
- orderMap.remove(key);
- }
-
- }
- log.info("------>{}", JSONObject.toJSONString(orderModelList));
- if (CollectionUtils.isEmpty(orderModelList)) {
- return;
- }
- System.out.println("本次执行的列表ASC");
- System.out.println(JSONObject.toJSONString(orderModelList));
- // 根据订单的类型发送消息
- // 3:开空 7:爆仓平空
- // 9:止盈平多 12:止损平空
- for (OrderModel model : orderModelList) {
- // 止损平空
- List<OrderModel> kkzsList = new ArrayList<OrderModel>();
- // 止盈平多
- List<OrderModel> kdzyList = new ArrayList<OrderModel>();
- // 爆仓平空
- List<OrderModel> bcList = new ArrayList<OrderModel>();
- // 开空
- List<OrderModel> wtkkList = new ArrayList<OrderModel>();
- switch (model.getType()) {
- case 3:
- wtkkList.add(model);
- break;
- case 7:
- bcList.add(model);
- break;
- case 9:
- kdzyList.add(model);
- break;
- case 12:
- kkzsList.add(model);
- break;
- default:
- log.info("#price-service unknown type#");
- break;
- }
-
- // 发送消息
- if (CollectionUtils.isNotEmpty(kkzsList)) {
- String kkzs = JSONObject.toJSONString(kkzsList);
- orderProducer.sendLessLoss(kkzs);
- }
- if (CollectionUtils.isNotEmpty(kdzyList)) {
- String kdzy = JSONObject.toJSONString(kdzyList);
- orderProducer.sendMorePro(kdzy);
- }
- if (CollectionUtils.isNotEmpty(bcList)) {
- orderProducer.sendCoinout(JSONObject.toJSONString(bcList));
- }
- if (CollectionUtils.isNotEmpty(wtkkList)) {
- orderProducer.sendLimit(JSONObject.toJSONString(wtkkList));
- }
- }
- }
- }
-
- // 处理消息 正序的 包括
- // 1:买入委托2:开多3:开空4:平多5:平空6:爆仓平多7:爆仓平空8:撤单9:止盈平多10:止盈平空11:止损平多12:止损平空
- public void dealDescPriceOrderAndSenMq(List<DescBigDecimal> list, String symbol) {
- if (CollectionUtils.isNotEmpty(list)) {
- // 根据不同类型发送不同消息 1 倒序 2 正序
- List<OrderModel> orderModelList = new ArrayList<OrderModel>();
- Map<String, List<OrderModel>> orderMap = PricePriorityQueue.getOrderMap(symbol, 2);
- // 根据价格查询到对应的订单
- for (DescBigDecimal desc : list) {
- String key = desc.getValue().toPlainString();
- assert orderMap != null;
- log.info("----->->{}, --> {}", JSONObject.toJSONString(orderMap), key);
- if (orderMap.containsKey(key)) {
- orderModelList.addAll(orderMap.get(key));
- orderMap.remove(key);
- }
-
- }
-
- if (CollectionUtils.isEmpty(orderModelList)) {
- return;
- }
- System.out.println("本次执行的列表Desc");
- System.out.println(JSONObject.toJSONString(orderModelList));
- // 根据订单的类型发送消息
- // 2:开多6:爆仓平多
- // 10:止盈平空11:止损平多
- for (OrderModel model : orderModelList) {
- // 开空止盈
- List<OrderModel> kkzyList = new ArrayList<OrderModel>();
- // 开多止损
- List<OrderModel> kdzsList = new ArrayList<OrderModel>();
- // 爆仓
- List<OrderModel> bcList = new ArrayList<OrderModel>();
- // 开多委托
- List<OrderModel> wtkdList = new ArrayList<OrderModel>();
- switch (model.getType()) {
- case 2:
- wtkdList.add(model);
- break;
- case 6:
- bcList.add(model);
- break;
- case 10:
- kkzyList.add(model);
- break;
- case 11:
- kdzsList.add(model);
- break;
- default:
- break;
- }
-
- // 发送消息
- if (CollectionUtils.isNotEmpty(kkzyList)) {
- String kkzy = JSONObject.toJSONString(kkzyList);
- orderProducer.sendLessPro(kkzy);
- }
- if (CollectionUtils.isNotEmpty(kdzsList)) {
- String kdzs = JSONObject.toJSONString(kdzsList);
- orderProducer.sendMoreLoss(kdzs);
- }
- if (CollectionUtils.isNotEmpty(bcList)) {
- orderProducer.sendCoinout(JSONObject.toJSONString(bcList));
- }
- if (CollectionUtils.isNotEmpty(wtkdList)) {
- orderProducer.sendLimit(JSONObject.toJSONString(wtkdList));
-
- }
- }
- }
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/producer/OrderProducer.java b/src/main/java/com/xcong/excoin/rabbit/producer/OrderProducer.java
deleted file mode 100644
index 400cf46..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/producer/OrderProducer.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.xcong.excoin.rabbit.producer;
-
-import com.xcong.excoin.configurations.RabbitMqConfig;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.amqp.rabbit.connection.CorrelationData;
-import org.springframework.amqp.rabbit.core.RabbitTemplate;
-import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.util.UUID;
-
-
-/**
- * rabbitMq示例生产者
- */
-@Slf4j
-@Component
-public class OrderProducer implements ConfirmCallback {
-
- /**
- * 配置中配置的RabbitTemplate的是prototype类型,不能直接注入
- */
- private RabbitTemplate rabbitTemplate;
-
- /**
- * 在构造方法上注入RabbitTemplate
- *
- * @param
- */
- @Autowired
- public OrderProducer(RabbitTemplate rabbitTemplate) {
- this.rabbitTemplate = rabbitTemplate;
- rabbitTemplate.setConfirmCallback(this);
- }
-
- /**
- * P发送消息方法 开多止盈
- */
- public void sendMorePro(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- System.out.println("发送开多止盈:" + content + "==pid:" + correlationData.getId());
-
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_MOREPRO, content, correlationData);
- }
-
- /**
- * 开空止盈
- *
- * @param content
- */
- public void sendLessPro(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- System.out.println("发送开空止盈:" + content + "==pid:" + correlationData.getId());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_LESSPRO, content, correlationData);
- }
-
- /**
- * 开多止损
- *
- * @param content
- */
- public void sendMoreLoss(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- System.out.println("发送开多止损:" + content + "==pid:" + correlationData.getId());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_MORELOSS, content, correlationData);
- }
-
- /**
- * 开空止损
- *
- * @param content
- */
- public void sendLessLoss(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- System.out.println("发送开空止损:" + content + "==pid:" + correlationData.getId());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_LESSLOSS, content, correlationData);
- }
-
- /**
- * 发送委托交易消息
- *
- * @param content
- */
- public void sendLimit(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- System.out.println("发送限价委托:" + content + "==pid:" + correlationData.getId());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_LIMIT, content, correlationData);
- }
-
- /**
- * 发送爆仓消息
- *
- * @param content
- */
- public void sendCoinout(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- System.out.println("发送爆仓:" + content + "==pid:" + correlationData.getId());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_COINOUT, content, correlationData);
- }
-
-
- /**
- * 发送价格操作消息
- *
- * @param content
- */
- public void sendPriceOperate(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- log.info("发送价格操作 : {}==pid : {}", content, correlationData.getId());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_PRICEOPERATE, content, correlationData);
- }
-
- /**
- * 发送平仓
- *
- * @param content
- */
- public void sendCloseTrade(String content) {
- CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
- log.info("发送平仓消息:{}==pid : {}", content, correlationData.getId());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_CLOSETRADE, content, correlationData);
- }
-
-
- /**
- * 用于确认消息是否成功发送到队列
- */
- @Override
- public void confirm(CorrelationData correlationData, boolean ack, String cause) {
- if (ack) {
- //System.out.println("消息发送成功"+correlationData.getId());
- //LogUtil.info("消息发送成功,correlationId={}", correlationData.getId());
- } else {
- System.out.println("消息发送失败" + correlationData.getId());
- //LogUtil.info("消息发送失败,correlationId={}", correlationData.getId());
- }
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/rabbit/producer/TestProducer.java b/src/main/java/com/xcong/excoin/rabbit/producer/TestProducer.java
deleted file mode 100644
index 00ffd52..0000000
--- a/src/main/java/com/xcong/excoin/rabbit/producer/TestProducer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.xcong.excoin.rabbit.producer;
-
-import cn.hutool.core.util.IdUtil;
-import com.xcong.excoin.configurations.RabbitMqConfig;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.amqp.rabbit.connection.CorrelationData;
-import org.springframework.amqp.rabbit.core.RabbitTemplate;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * @author wzy
- * @date 2020-05-25
- **/
-@Slf4j
-@Component
-public class TestProducer implements RabbitTemplate.ConfirmCallback {
-
- private RabbitTemplate rabbitTemplate;
-
- @Autowired
- public TestProducer(RabbitTemplate rabbitTemplate) {
- this.rabbitTemplate = rabbitTemplate;
- rabbitTemplate.setConfirmCallback(this);
- }
-
- public void sendTestMsg(String content) {
- CorrelationData correlationData = new CorrelationData(IdUtil.simpleUUID());
- rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_ONE, RabbitMqConfig.ROUTING_KEY_TEST, content, correlationData);
- }
-
-
- @Override
- public void confirm(CorrelationData correlationData, boolean ack, String cause) {
- log.info("#----->{}#", correlationData);
- if (ack) {
- log.info("success");
- } else {
- log.info("--->{}", cause);
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/utils/CacheSettingUtils.java b/src/main/java/com/xcong/excoin/utils/CacheSettingUtils.java
deleted file mode 100644
index 9145008..0000000
--- a/src/main/java/com/xcong/excoin/utils/CacheSettingUtils.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.xcong.excoin.utils;
-
-import cn.hutool.core.bean.BeanUtil;
-import com.xcong.excoin.modules.platform.dao.TradeSettingDao;
-import com.xcong.excoin.modules.platform.entity.PlatformSymbolsSkuEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import org.apache.commons.collections.CollectionUtils;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author wzy
- * @date 2020-05-28
- **/
-@Component
-public class CacheSettingUtils {
-
-
- /**
- * 交易设置缓存Key
- */
- private final static String TRADE_SETTING_KEY = "trade_setting_key";
-
- /**
- * 币种规格缓存key
- */
- private final static String TRADE_SYMBOL_SKU_KEY = "trade_symbol_sku_key";
-
- @Resource
- private TradeSettingDao tradeSettingDao;
-
- @Resource
- private RedisUtils redisUtils;
-
-
- /**
- * 获取币种规格
- *
- * @param symbol
- * @return
- */
- public BigDecimal getSymbolSku(String symbol) {
- Object hget = redisUtils.hget(TRADE_SYMBOL_SKU_KEY, symbol);
- if (hget == null) {
- List<PlatformSymbolsSkuEntity> symbolSkubySymbol = tradeSettingDao.findAllSymbolSkubySymbol();
- Map<String, Object> map = new HashMap<String, Object>();
- if (CollectionUtils.isNotEmpty(symbolSkubySymbol)) {
- for (PlatformSymbolsSkuEntity symbolSku : symbolSkubySymbol) {
- map.put(symbolSku.getName(), symbolSku.getLotnumber());
- }
- // 存入redis
- redisUtils.hmset(TRADE_SYMBOL_SKU_KEY, map);
- }
-
- hget = redisUtils.hget(TRADE_SYMBOL_SKU_KEY, symbol);
- }
-
- return new BigDecimal(hget.toString());
- }
-
- /**
- * 获取交易设置缓存
- *
- * @return
- */
- public PlatformTradeSettingEntity getTradeSetting() {
- Map<Object, Object> hmget = redisUtils.hmget(TRADE_SETTING_KEY);
-
- if (hmget == null || hmget.size() == 0) {
- PlatformTradeSettingEntity tradeSetting = tradeSettingDao.findTradeSetting();
- redisUtils.hmset(TRADE_SETTING_KEY, BeanUtil.beanToMap(tradeSetting));
- return tradeSetting;
- }
- return BeanUtil.mapToBean(hmget, PlatformTradeSettingEntity.class, true);
- }
-
-}
diff --git a/src/main/java/com/xcong/excoin/utils/CalculateUtil.java b/src/main/java/com/xcong/excoin/utils/CalculateUtil.java
deleted file mode 100644
index 0ef6ae6..0000000
--- a/src/main/java/com/xcong/excoin/utils/CalculateUtil.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.xcong.excoin.utils;
-
-
-import com.xcong.excoin.modules.member.dao.MemberSettingDao;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberSettingEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-
-/**
- * @author helius
- */
-@Slf4j
-public class CalculateUtil {
-
- /**
- * 计算预估强平价
- *
- * @param bondAmount 保证金
- * @param openPrice 开仓价
- * @param symbolSkuNumber 张数
- * @param lotNumber 规格
- * @param type 1:买多2:卖空
- * @return
- */
- public static BigDecimal getForceSetPrice(BigDecimal bondAmount, BigDecimal openPrice, int symbolSkuNumber, BigDecimal lotNumber,
- int type, MemberEntity member) {
- MemberSettingDao memberSettingDao = SpringContextHolder.getBean(MemberSettingDao.class);
- BigDecimal forcePrice = BigDecimal.ZERO;
- BigDecimal money = bondAmount.divide(new BigDecimal(symbolSkuNumber).multiply(lotNumber), 8, BigDecimal.ROUND_DOWN);
- if (member.getIsForce() == 1) {
- MemberSettingEntity memberSetting = memberSettingDao.selectMemberSettingByMemberId(member.getId());
- money = money.multiply(memberSetting.getForceParam().multiply(BigDecimal.valueOf(100)));
- }
- //卖空
- if (type == 2) {
- forcePrice = money.add(openPrice);
- } else {//开多
- forcePrice = openPrice.subtract(money);
- }
- if (forcePrice.compareTo(BigDecimal.ZERO) < 0) {
- forcePrice = BigDecimal.ZERO;
- }
- return forcePrice;
- }
-}
diff --git a/src/main/java/com/xcong/excoin/utils/CoinTypeConvert.java b/src/main/java/com/xcong/excoin/utils/CoinTypeConvert.java
deleted file mode 100644
index 560eca7..0000000
--- a/src/main/java/com/xcong/excoin/utils/CoinTypeConvert.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.xcong.excoin.utils;
-
-/**
- * @author wzy
- * @date 2020-05-28
- **/
-public class CoinTypeConvert {
-
- public static String convert(String symbol) {
- switch (symbol) {
- case "btcusdt":
- return "BTC/USDT";
- case "ethusdt":
- return "ETH/USDT";
- case "xrpusdt":
- return "XRP/USDT";
- case "ltcusdt":
- return "LTC/USDT";
- case "bchusdt":
- return "BCH/USDT";
- case "eosusdt":
- return "EOS/USDT";
- case "etcusdt":
- return "ETC/USDT";
- default:
- return null;
- }
- }
-
- public static String okxConvert(String symbol) {
- //将xxx-USDT转换成xxx/USDT
- if (symbol.contains("-")) {
- symbol = symbol.replace("-", "/");
- }
-
- return symbol;
- }
-
- public static String convertToKey(String symbol) {
- switch (symbol) {
- case "BTC/USDT":
- return "BTC_NEW_PRICE";
- case "ETH/USDT":
- return "ETH_NEW_PRICE";
- case "XRP/USDT":
- return "XRP_NEW_PRICE";
- case "LTC/USDT":
- return "LTC_NEW_PRICE";
- case "BCH/USDT":
- return "BCH_NEW_PRICE";
- case "EOS/USDT":
- return "EOS_NEW_PRICE";
- case "ETC/USDT":
- return "ETC_NEW_PRICE";
- default:
- return null;
- }
- }
-}
diff --git a/src/main/java/com/xcong/excoin/utils/LogRecordUtils.java b/src/main/java/com/xcong/excoin/utils/LogRecordUtils.java
deleted file mode 100644
index 6bf4189..0000000
--- a/src/main/java/com/xcong/excoin/utils/LogRecordUtils.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin.utils;
-
-import com.xcong.excoin.modules.coin.dao.MemberAccountFlowEntityDao;
-import com.xcong.excoin.modules.coin.dao.MemberAccountMoneyChangeDao;
-import com.xcong.excoin.modules.coin.entity.MemberAccountFlowEntity;
-import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange;
-
-import java.math.BigDecimal;
-
-/**
- * 日志记录工具类
- *
- * @author wzy
- * @date 2020-07-02
- **/
-public class LogRecordUtils {
-
- public static void insertMemberAccountMoneyChange(Long memberId,String content, BigDecimal amount, String symbol, Integer status, Integer type) {
- MemberAccountMoneyChange accountRecord = new MemberAccountMoneyChange();
- accountRecord.setContent(content);
- accountRecord.setMemberId(memberId);
- accountRecord.setAmount(amount);
- accountRecord.setStatus(status);
- accountRecord.setSymbol(symbol);
- accountRecord.setType(type);
- SpringContextHolder.getBean(MemberAccountMoneyChangeDao.class).insert(accountRecord);
- }
-
- public static void insertMemberAccountFlow(Long memberId, BigDecimal price, BigDecimal balance, String symbol, String source, String remark) {
- MemberAccountFlowEntity memberAccountFlowEntity = new MemberAccountFlowEntity();
- memberAccountFlowEntity.setMemberId(memberId);
- memberAccountFlowEntity.setPrice(price);
- memberAccountFlowEntity.setBalance(balance);
- memberAccountFlowEntity.setSymbol(symbol);
- memberAccountFlowEntity.setSource(source);
- memberAccountFlowEntity.setRemark(remark);
- SpringContextHolder.getBean(MemberAccountFlowEntityDao.class).insert(memberAccountFlowEntity);
- }
-}
diff --git a/src/main/java/com/xcong/excoin/utils/OssUtils.java b/src/main/java/com/xcong/excoin/utils/OssUtils.java
deleted file mode 100644
index eb9cc89..0000000
--- a/src/main/java/com/xcong/excoin/utils/OssUtils.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.xcong.excoin.utils;
-
-import com.aliyun.oss.OSS;
-import lombok.extern.slf4j.Slf4j;
-import sun.misc.BASE64Decoder;
-
-import java.io.ByteArrayInputStream;
-
-/**
- * @author wzy
- * @date 2020-05-22
- **/
-@Slf4j
-public class OssUtils {
-
- private static final OSS OSS_CLIENT = (OSS) SpringContextHolder.getBean("ossClient");
-
- public static boolean uploadFileWithBase64(String base64, String pathName) {
- ByteArrayInputStream stream = null;
- try {
- BASE64Decoder decoder = new BASE64Decoder();
- byte[] bytes = decoder.decodeBuffer(base64);
- stream = new ByteArrayInputStream(bytes);
- OSS_CLIENT.putObject("excoin", pathName, stream);
- return true;
- } catch (Exception e) {
- log.error("#上传失败:{}#", e);
- return false;
- }
- }
-
-
-}
diff --git a/src/main/java/com/xcong/excoin/utils/ThreadPoolUtils.java b/src/main/java/com/xcong/excoin/utils/ThreadPoolUtils.java
deleted file mode 100644
index 10c1e06..0000000
--- a/src/main/java/com/xcong/excoin/utils/ThreadPoolUtils.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.xcong.excoin.utils;
-
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.service.impl.OrderWebsocketServiceImpl;
-import com.xcong.excoin.utils.dingtalk.DingTalkUtils;
-
-import java.math.BigDecimal;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * @author wzy
- * @date 2020-06-01
- **/
-public class ThreadPoolUtils {
-
- public static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(20);
-
- /**
- * 计算佣金
- *
- * @param id 用户ID
- * @param price 手续费
- * @param entity 订单实体
- * @param type 订单类型
- */
- public static void calReturnMoney(Long id, BigDecimal price, ContractOrderEntity entity, int type) {
- OrderWebsocketServiceImpl orderWebsocketService = SpringContextHolder.getBean(OrderWebsocketServiceImpl.class);
- EXECUTOR.execute(new Runnable() {
- @Override
- public void run() {
- orderWebsocketService.calYj(id, price, entity, type);
- }
- });
- }
-
- /**
- * 发送钉钉消息
- *
- * @param type 类型
- */
- public static void sendDingTalk(int type) {
- EXECUTOR.execute(new Runnable() {
- @Override
- public void run() {
- DingTalkUtils.sendActionCard(type);
- }
- });
- }
-}
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
index 91f5dcc..00fa858 100644
--- a/src/main/resources/application-test.yml
+++ b/src/main/resources/application-test.yml
@@ -102,7 +102,7 @@
rabbit-consumer: false
block-job: false
websocket: false
- quant: false
+ quant: true
aliyun:
oss:
diff --git a/src/test/java/com/xcong/excoin/GuijiTest.java b/src/test/java/com/xcong/excoin/GuijiTest.java
deleted file mode 100644
index 6b99989..0000000
--- a/src/test/java/com/xcong/excoin/GuijiTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.xcong.excoin;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-import javax.annotation.Resource;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.modules.blackchain.service.EthService;
-import com.xcong.excoin.modules.member.dao.MemberCoinAddressDao;
-import com.xcong.excoin.modules.member.dao.MemberCoinChargeDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
-import com.xcong.excoin.modules.member.entity.MemberCoinAddressEntity;
-import com.xcong.excoin.modules.member.entity.MemberCoinChargeEntity;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.StrUtil;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@SpringBootTest
-public class GuijiTest {
-
- private static final BigDecimal LIMIT = new BigDecimal("50");
- private static final BigDecimal FEE = new BigDecimal("0.005");
-
- public static String ETH_FEE = "0.005";
-
- public static final String TOTAL_ADDRESS = "0x067b4bE5d7B05560AE539Fc8f10597D854ae056D";
- public static final String TOTAL_PRIVATE = "1fb7288c8c88c37d6f79e9617822bffc8d3635bf2d808c5f6afdee9bb326e49c";
-
- @Resource
- private MemberCoinChargeDao memberCoinChargeDao;
- @Resource
- private MemberCoinAddressDao memberCoinAddressDao;
- @Resource
- private MemberWalletCoinDao memberWalletCoinDao;
-
- public void pool() throws ExecutionException, InterruptedException {
- //List<MemberCoinChargeEntity> list = memberCoinChargeDao.selectAllBySymbolAndTag(CoinTypeEnum.USDT.name(), "ERC20", 1);
- List<MemberCoinChargeEntity> list = new ArrayList<MemberCoinChargeEntity>();
- MemberCoinChargeEntity coin = new MemberCoinChargeEntity();
- coin.setAddress("0xdf24223ab4599a47aa9383c5c9914edd68ae63dc");
- coin.setMemberId(1L);
- coin.setLastAmount(new BigDecimal(51.01000101));
- list.add(coin);
- if (CollUtil.isNotEmpty(list)) {
- EthService ethService = new EthService();
-
- for (MemberCoinChargeEntity coinCharge : list) {
- // 首先根据每个地址查询其是否有ETH 如果没有就充值ETH并设置1 表示初始状态 status=2(待充值)3:表示已提过
- String address = coinCharge.getAddress();
- Long memberId = coinCharge.getMemberId();
- BigDecimal lastAmount = coinCharge.getLastAmount();
- if (lastAmount == null || lastAmount.compareTo(LIMIT) < 0) {
- continue;
- }
-
- BigDecimal usdt = ethService.tokenGetBalance(address);
- System.out.println("地址:{}, 金额:{}"+address+" usdt="+usdt);
- if (usdt != null && usdt.compareTo(LIMIT) > 0) {
- usdt = usdt.subtract(new BigDecimal("0.01"));
-
- // 查询eth是否足够
- BigDecimal eth = EthService.getEthBlance(address);
- System.out.println("地址:"+address+" eth = "+eth);
- if (eth != null && eth.compareTo(FEE) >= 0) {
- MemberCoinAddressEntity memberCoinAddressEntity = memberCoinAddressDao.selectBlockAddressWithTag(memberId, CoinTypeEnum.USDT.name(), "ERC20");
- if (memberCoinAddressEntity == null) {
- continue;
- }
-
- String privateKey = memberCoinAddressEntity.getPrivateKey();
-
- usdt = usdt.multiply(new BigDecimal("1000000"));
- String usdtStr = usdt.toPlainString();
- if (usdtStr.contains(".")) {
- usdtStr = usdtStr.substring(0, usdtStr.lastIndexOf("."));
- }
-
- String hash = ethService.tokenSend(privateKey, address, TOTAL_ADDRESS, usdtStr);
- System.out.println("归集:"+hash);
- if (StrUtil.isNotBlank(hash)) {
- // 归集成功更新状态 先保存本次的hash值,待交易成功后再更新
- coinCharge.setHash(hash);
- memberCoinChargeDao.updateById(coinCharge);
- }
- } else {
- String hash = ethService.ethSend(TOTAL_PRIVATE, TOTAL_ADDRESS, address, ETH_FEE);
- System.out.println("转手续费:"+hash);
- }
- }
- }
- }
- }
- /**
- * 向特定账号转手续费
- */
- @Test
- public void pushFee() {
- String toAddress = "0xbc6050a2898511bda406660267e6667448070552";
- EthService ethService = new EthService();
- try {
- String hash = ethService.ethSend(TOTAL_PRIVATE, TOTAL_ADDRESS, toAddress, "0.0032");
- System.out.println("转手续费:"+hash);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ExecutionException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
-
-
-}
-
diff --git a/src/test/java/com/xcong/excoin/HuobiTest.java b/src/test/java/com/xcong/excoin/HuobiTest.java
deleted file mode 100644
index 1491015..0000000
--- a/src/test/java/com/xcong/excoin/HuobiTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xcong.excoin;
-
-import com.alibaba.fastjson.JSONObject;
-import com.huobi.client.SubscriptionClient;
-import com.huobi.client.SubscriptionOptions;
-import com.huobi.client.model.Candlestick;
-import com.huobi.client.model.enums.CandlestickInterval;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-/**
- * @author wzy
- * @date 2020-05-22
- **/
-@Slf4j
-@SpringBootTest
-public class HuobiTest {
-
- @Test
- public void websocketTest() {
- }
-
- public static void main(String[] args) {
- System.out.println("========价格更新开启=======");
- SubscriptionOptions subscriptionOptions = new SubscriptionOptions();
- //3秒重试
- subscriptionOptions.setConnectionDelayOnFailure(5);
- subscriptionOptions.setUri("wss://api.hadax.com/ws");
- SubscriptionClient subscriptionClient = SubscriptionClient.create("", "", subscriptionOptions);
-// subscriptionClient.subscribeTradeEvent("btcusdt,ethusdt,xrpusdt,ltcusdt,bchusdt,eosusdt,etcusdt", tradeEvent -> {
-// log.info("{}", JSONObject.toJSONString(tradeEvent));
-// });
-
- subscriptionClient.subscribeCandlestickEvent("btcusdt,ethusdt,eosusdt,etcusdt,ltcusdt,bchusdt,xrpusdt", CandlestickInterval.DAY1, (candlestickEvent) -> {
- log.info("{}", JSONObject.toJSONString(candlestickEvent));
- });
- }
-}
\ No newline at end of file
diff --git a/src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java b/src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java
deleted file mode 100644
index d532e17..0000000
--- a/src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.xcong.excoin;
-
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.common.enumerates.SymbolEnum;
-import com.xcong.excoin.configurations.properties.AliOssProperties;
-import com.xcong.excoin.modules.coin.service.BlockCoinService;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.service.ContractHoldOrderService;
-import com.xcong.excoin.modules.test.dao.TestUserDao;
-import com.xcong.excoin.modules.test.entity.TestUserEntity;
-import com.xcong.excoin.modules.test.service.TestUserService;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import javax.annotation.Resource;
-import java.util.Date;
-import java.util.List;
-
-@Slf4j
-@SpringBootTest
-class KssframeworkApplicationTests {
-
- @Resource
- private TestUserDao testUserDao;
-
- @Test
- public void testUserInsert() {
- for (int i = 0; i < 20; i++) {
- TestUserEntity testUser = new TestUserEntity();
- testUser.setCreateBy("123");
- testUser.setCreateTime(new Date());
- testUser.setUpdateBy("123");
- testUser.setUpdateTime(new Date());
- testUser.setAccount("12345" + i);
- testUser.setName("hehe" + i);
- testUser.setPassword("33333");
- testUserDao.insert(testUser);
- }
-
- }
-
- @Resource
- TestUserService testUserService;
-
- @Test
- public void mybatisInterceptorTest() {
- TestUserEntity testUser = new TestUserEntity();
- testUser.setId(3L);
- testUser.setAccount("123333345");
- testUser.setName("hehe111");
- testUser.setPassword("33333");
-
- testUserDao.updateById(testUser);
-
- }
-
- @Test
- public void enumTest() {
- System.out.println(SymbolEnum.BCH.getValue());
- }
-
- @Resource
- AliOssProperties aliOssProperties;
-
- @Test
- public void aliyunOssTest() {
- log.info("{}", aliOssProperties.getEndPoint());
- }
-
-
- @Resource
- private BlockCoinService blockCoinService;
-
- @Test
- public void usdtEthTest() {
- blockCoinService.updateEthUsdt();
- }
-
- @Resource
- ContractHoldOrderService contractHoldOrderService;
-
- @Test
- public void coinOutTest() {
- List<ContractHoldOrderEntity> list = contractHoldOrderService.selectContractHoldOrderByBatchNo("7948d5f5-222d-44db-bd60-69dbe762dc38");
- log.info("--->{}", list);
- log.info("------>{}", list.get(0).getId());
- }
-
-}
diff --git a/src/test/java/com/xcong/excoin/MemberSettingTest.java b/src/test/java/com/xcong/excoin/MemberSettingTest.java
deleted file mode 100644
index 68461c2..0000000
--- a/src/test/java/com/xcong/excoin/MemberSettingTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.xcong.excoin;
-
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.dao.MemberSettingDao;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberSettingEntity;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author wzy
- * @date 2020-08-13
- **/
-@Slf4j
-@SpringBootTest
-public class MemberSettingTest {
-
- @Resource
- private MemberDao memberDao;
- @Resource
- private MemberSettingDao memberSettingDao;
-
- @Test
- public void settingDateTest() {
- Map<String, Object> map = new HashMap<>();
- List<MemberEntity> memberEntities = memberDao.selectByMap(map);
- log.info("--->{}", memberEntities.size());
-
- List<MemberSettingEntity> list = new ArrayList<>();
- for (MemberEntity memberEntity : memberEntities) {
- MemberSettingEntity memberSettingEntity = new MemberSettingEntity();
- memberSettingEntity.setCreateBy("system");
- memberSettingEntity.setUpdateBy("system");
- memberSettingEntity.setMemberId(memberEntity.getId());
- memberSettingEntity.setClosingSpread(memberEntity.getClosingSpread());
- memberSettingEntity.setForceParam(memberEntity.getForceParam());
- memberSettingEntity.setSpread(memberEntity.getSpread());
- list.add(memberSettingEntity);
- }
-
- memberSettingDao.batchInsert(list);
- }
-}
diff --git a/src/test/java/com/xcong/excoin/RSATest.java b/src/test/java/com/xcong/excoin/RSATest.java
deleted file mode 100644
index 45c6488..0000000
--- a/src/test/java/com/xcong/excoin/RSATest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.xcong.excoin;
-
-import cn.hutool.core.codec.Base64;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.HexUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
-import cn.hutool.crypto.asymmetric.Sign;
-import cn.hutool.crypto.asymmetric.SignAlgorithm;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import java.math.BigDecimal;
-import java.security.KeyPair;
-
-/**
- * @author wzy
- * @date 2020-05-12
- **/
-@Slf4j
-@SpringBootTest
-public class RSATest {
-
- private String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFU26floADA4PSEmE99u1YD30P3LAP6c7XYRASejCte+uOUfveSGHip2cgwpElu4y/r8PKAbclvs8j3y0g4MhjQbRjsiK8O2PKPaTWW+bHWPapPAhTuRHDMVFV6sajZ4dcg7mZ9+zPqG2RkvXi993v7kcTYq8hpE20/+Do7gwFowIDAQAB";
-
- private String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIVTbp+WgAMDg9ISYT327VgPfQ/csA/pztdhEBJ6MK17645R+95IYeKnZyDCkSW7jL+vw8oBtyW+zyPfLSDgyGNBtGOyIrw7Y8o9pNZb5sdY9qk8CFO5EcMxUVXqxqNnh1yDuZn37M+obZGS9eL33e/uRxNiryGkTbT/4OjuDAWjAgMBAAECgYAUw8TD6C2xyndaXXB1tSKMB4WD1ew53kFPvBdDuXIhYt5yAQTIPt+37DicmpD+nnIyXI6SxKegolIilRyzNS8gQqXyqnj+UrIX8hJp0bxwEx2epcKAcwn84XFEXFGMFe2POUpFgNkxbKcWH9UNAALsO20ipP3UB6dj832HjGSagQJBAPKeVrXTnEf0Ien2A4jXAX4WZp0x7pg9ccGRo8RKFUrY0xVGstKEpCTTdDZ596/L8EN83dP2reHl2sCJpzC5NsECQQCMre6tadDg/cZE7SbxGhxlIRM1SyqGnxk+owiQbiYKLlhNR5GEZUdh+xubjtWPWhmXiy3nmFki9NESIhWf0xljAkAD/LAmGs0lrZBlHOLf+9CNdubGzIxEOjZFXRRY5HLHIRsO7XOA3CcqZ8MwJf75B5vyL/ohQpuG69UVdu2lclXBAkBq0/4Gc+9pm2y/lLNYrXJYnWg/tSfC+Pgrp5RuUSbT3mOxs6JePqaZUh2h4DJuXIZInSkr0HYH5I8LTRTMvHpvAkEAl81YqDl/deSXAq4Xy38/UrMTSEwGmHtVTxlwJ9Of+iX+pSDu/TIi3ZJtjxL+P1IcJD5r89SgJnl6secBz9rPBQ==";
-
-
- @Test
- public void rsaTest() {
- KeyPair keyPair = SecureUtil.generateKeyPair("RSA");
- log.info("{}", Base64.encode(keyPair.getPublic().getEncoded()));
- log.info("{}", Base64.encode(keyPair.getPrivate().getEncoded()));
- }
-
-
- @Test
- public void aaTest() {
- RSA rsa = new RSA();
- String encrypt = new String(rsa.encrypt(StrUtil.bytes("1234567", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey));
- log.info("#---->{}#", encrypt);
-
- String decrypt = new String(rsa.decrypt(encrypt, KeyType.PrivateKey));
- log.info("#------>{}#", decrypt);
- }
-
- @Test
- public void enAndDenTest() {
- RSA rsa = new RSA();
-
- rsa.getPrivateKey();
- log.info(rsa.getPrivateKeyBase64());
- rsa.getPublicKey();
- log.info(rsa.getPublicKeyBase64());
-
- byte[] encrypt = rsa.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
- byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);
-
- log.info("---->{}", new String(encrypt));
- log.info("------>{}", new String(decrypt));
- }
-
- @Test
- public void decTest() {
- String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCf8UFZK54AiK4PRu7tNd+Z8qZ77o/QXCnk25DRmygVpOEu5mGNSAvfnWmKp2pEV2RljeXq3Rid/+LQkonaebMJeXKSF0yxL/VgyeT8JaQ5gNbOrdfdlc+mFkXJyzyJt8YkvApEdPRNSU2ENBn7mgRfD0BYPM4vZ6/rv+de38FJwIDAQAB";
- String str = "OsaRaZOuBYGiI1j62SQvJOj4CieiAFIdWRTQln2ZSAx1KHBhyCpJuLjb84ZuwsPd98crQOlE4VhgoQB/9SD5b1ATRGmpr6FR5FqXl76JDOirdYvrplJw3hO0cZM3ADL2TQTbtGanUskOWYPG+GXRdqV21und3aZXh+itTWcSFYw=";
- String privateKeys = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIJ/xQVkrngCIrg9G7u0135nypnvuj9BcKeTbkNGbKBWk4S7mYY1IC9+daYqnakRXZGWN5erdGJ3/4tCSidp5swl5cpIXTLEv9WDJ5PwlpDmA1s6t192Vz6YWRcnLPIm3xiS8CkR09E1JTYQ0GfuaBF8PQFg8zi9nr+u/517fwUnAgMBAAECgYBhPt9NvpI4wbanvnndLczr2GJkxfzvSE+vwLCJF4C5FusFHVsxZINggQcg1V75bwRgCiXRMyYefreCSdrCditS43PzTOmE4RRrpxLlm8oubJc0C98LQ2qlN9AsUqL5IHpVGgbHDyWAwjc1GBID6nwXKpxq1/VodFqhahG9D5EZsQJBALnkb+5VTxQbiyQI4Uc9NIvAyVcNY1OisbvY6tvNgdBbJkADgAb78M1HWxxYjUqsvzggNHc7cWqWBHMgpnJaqm8CQQCztze4D7uAk7OC9MJHY5eE980J8Kk+GEZKxz4LahzU6V6dcb9GFac3wEtgilj/tOAn9y0/Q8sm9vvCIbMDzgzJAkEAqRYcqhF26LdVDOX25DHMBgLKISDQZFbsjA13M4/usHL4i+mjHrc0BcUOHu59NpuDI65HitzLAUSLr5zXSdUmiQJAW77wOg4GCejdXsB3IhzMsHwU97sdm26nC+vVV9xvJZ6Rx8zW+f9543NOx9U5BCmhuaVtOvvwDU9PTVcI3atmSQJAXAIJ5gGdtXx0DXiX4VvzNFHqgaqHMGvXyjNVkU2FYQbSAd2A6app4uRO+BkZu9dSjh14m+oXMnV2HzAN2rRnjA==";
-
- RSA rsa = new RSA(privateKeys, null);
- String aaa = new String(rsa.decrypt(str, KeyType.PrivateKey));
- log.info("---->{}", aaa);
- }
-
- @Test
- public void demoTest() {
- String PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIL7pbQ+5KKGYRhw7jE31hmA"
- + "f8Q60ybd+xZuRmuO5kOFBRqXGxKTQ9TfQI+aMW+0lw/kibKzaD/EKV91107xE384qOy6IcuBfaR5lv39OcoqNZ"
- + "5l+Dah5ABGnVkBP9fKOFhPgghBknTRo0/rZFGI6Q1UHXb+4atP++LNFlDymJcPAgMBAAECgYBammGb1alndta"
- + "xBmTtLLdveoBmp14p04D8mhkiC33iFKBcLUvvxGg2Vpuc+cbagyu/NZG+R/WDrlgEDUp6861M5BeFN0L9O4hz"
- + "GAEn8xyTE96f8sh4VlRmBOvVdwZqRO+ilkOM96+KL88A9RKdp8V2tna7TM6oI3LHDyf/JBoXaQJBAMcVN7fKlYP"
- + "Skzfh/yZzW2fmC0ZNg/qaW8Oa/wfDxlWjgnS0p/EKWZ8BxjR/d199L3i/KMaGdfpaWbYZLvYENqUCQQCobjsuCW"
- + "nlZhcWajjzpsSuy8/bICVEpUax1fUZ58Mq69CQXfaZemD9Ar4omzuEAAs2/uee3kt3AvCBaeq05NyjAkBme8SwB0iK"
- + "kLcaeGuJlq7CQIkjSrobIqUEf+CzVZPe+AorG+isS+Cw2w/2bHu+G0p5xSYvdH59P0+ZT0N+f9LFAkA6v3Ae56OrI"
- + "wfMhrJksfeKbIaMjNLS9b8JynIaXg9iCiyOHmgkMl5gAbPoH/ULXqSKwzBw5mJ2GW1gBlyaSfV3AkA/RJC+adIjsRGg"
- + "JOkiRjSmPpGv3FOhl9fsBPjupZBEIuoMWOC8GXK/73DHxwmfNmN7C9+sIi4RBcjEeQ5F5FHZ";
-
- RSA rsa = new RSA(PRIVATE_KEY, null);
-
- String a = "2707F9FD4288CEF302C972058712F24A5F3EC62C5A14AD2FC59DAB93503AA0FA17113A020EE4EA35EB53F"
- + "75F36564BA1DABAA20F3B90FD39315C30E68FE8A1803B36C29029B23EB612C06ACF3A34BE815074F5EB5AA3A"
- + "C0C8832EC42DA725B4E1C38EF4EA1B85904F8B10B2D62EA782B813229F9090E6F7394E42E6F44494BB8";
-
- byte[] aByte = HexUtil.decodeHex(a);
- byte[] decrypt = rsa.decrypt(aByte, KeyType.PrivateKey);
- }
-
- @Test
- public void md5Test() {
- String md5str = SecureUtil.md5("123456");
- log.info("{}", md5str);
- }
-
- @Test
- public void bigdecimalTest() {
- BigDecimal bigDecimal = new BigDecimal("123.12345678").setScale(4, BigDecimal.ROUND_DOWN);
- log.info("--->{}", bigDecimal);
- }
-}
diff --git a/src/test/java/com/xcong/excoin/RabbitMqTest.java b/src/test/java/com/xcong/excoin/RabbitMqTest.java
deleted file mode 100644
index 32f820e..0000000
--- a/src/test/java/com/xcong/excoin/RabbitMqTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.xcong.excoin;
-
-import com.xcong.excoin.rabbit.pricequeue.WebsocketPriceService;
-import com.xcong.excoin.rabbit.producer.TestProducer;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import javax.annotation.Resource;
-
-/**
- * @author wzy
- * @date 2020-05-25
- **/
-@SpringBootTest
-public class RabbitMqTest {
-
- @Autowired
- private TestProducer testProducer;
- @Resource
- private WebsocketPriceService websocketPriceService;
-
- @Test
- public void sendTestMsg() {
- testProducer.sendTestMsg("this is test msg");
- }
-
- @Test
- public void bombTest() {
-
- websocketPriceService.comparePriceDesc("BTC/USDT", "9608");
- }
-}
diff --git a/src/test/java/com/xcong/excoin/RedisTest.java b/src/test/java/com/xcong/excoin/RedisTest.java
deleted file mode 100644
index 116d9e7..0000000
--- a/src/test/java/com/xcong/excoin/RedisTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.xcong.excoin;
-
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-
-import javax.annotation.Resource;
-
-/**
- * @author wzy
- * @date 2020-07-15
- **/
-@Slf4j
-@SpringBootTest
-public class RedisTest {
-
- @Resource
- private MemberDao memberDao;
-
- @Resource
- private RedisUtils redisUtils;
-
- @Test
- public void redisResetTest() {
- MemberEntity member = memberDao.selectById(72L);
- member.setPassword(new BCryptPasswordEncoder().encode(member.getPassword()));
- redisUtils.set("app_21c8fb68f5de4bbfb91a03813833db8a", JSONObject.toJSONString(member), 36000);
- }
-
-}
diff --git a/src/test/java/com/xcong/excoin/ReturnMoneyTest.java b/src/test/java/com/xcong/excoin/ReturnMoneyTest.java
deleted file mode 100644
index eb40f55..0000000
--- a/src/test/java/com/xcong/excoin/ReturnMoneyTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.xcong.excoin;
-
-import cn.hutool.core.collection.CollUtil;
-import jnr.ffi.annotations.IgnoreError;
-
-import com.xcong.excoin.modules.coin.dao.MemberAccountMoneyChangeDao;
-import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange;
-import com.xcong.excoin.modules.contract.dao.ContractOrderDao;
-import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
-import com.xcong.excoin.modules.contract.service.impl.OrderWebsocketServiceImpl;
-import com.xcong.excoin.modules.member.dao.AgentReturnDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletAgentDao;
-import com.xcong.excoin.modules.member.entity.AgentReturnEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletAgentEntity;
-import com.xcong.excoin.utils.SpringContextHolder;
-import com.xcong.excoin.utils.ThreadPoolUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-06-30
- **/
-@Slf4j
-@SpringBootTest
-public class ReturnMoneyTest {
-
- @Resource
- private ContractOrderDao contractOrderDao;
- @Resource
- private AgentReturnDao agentReturnDao;
- @Resource
- private MemberWalletAgentDao memberWalletAgentDao;
- @Resource
- private MemberAccountMoneyChangeDao memberAccountMoneyChangeDao;
-
- /*@Test
- public void returnTest() {
- ContractOrderEntity entity = contractOrderDao.selectById(667L);
- OrderWebsocketServiceImpl orderWebsocketService = SpringContextHolder.getBean(OrderWebsocketServiceImpl.class);
- orderWebsocketService.calYj(19L, new BigDecimal(4.18004236), entity, AgentReturnEntity.ORDER_TYPE_OPEN);
- }*/
-
-
- @Test
- public void moneyReturnTest() {
- List<AgentReturnEntity> list = agentReturnDao.selectAllNeedMoneyReturn();
- log.info("返佣条数:{}", list.size());
- if (CollUtil.isNotEmpty(list)) {
- for (AgentReturnEntity agentReturn : list) {
- BigDecimal needReturn = agentReturn.getReturnAmount();
- Long refererId = agentReturn.getRefererId();
- MemberWalletAgentEntity walletAgent = memberWalletAgentDao.selectWalletAgentBymIdAndCode(refererId, "USDT");
- if (walletAgent == null) {
- continue;
- }
-
- log.info("用户ID:{}, 当前余额:{},总金额:{}, 返佣金额:{}", refererId, walletAgent.getAvailableBalance().toPlainString(), walletAgent.getTotalBalance().toPlainString(), needReturn);
- walletAgent.setAvailableBalance(walletAgent.getAvailableBalance().add(needReturn));
- walletAgent.setTotalBalance(walletAgent.getTotalBalance().add(needReturn));
-
-
- MemberAccountMoneyChange moneyChange = new MemberAccountMoneyChange();
- moneyChange.setAmount(needReturn);
- moneyChange.setContent("佣金到账");
- moneyChange.setType(MemberAccountMoneyChange.TYPE_WALLET_AGENT);
- moneyChange.setStatus(MemberAccountMoneyChange.STATUS_SUCCESS_INTEGER);
- moneyChange.setMemberId(refererId);
- moneyChange.setSymbol("USDT");
-
-// // 更新代理钱包金额
- memberWalletAgentDao.updateById(walletAgent);
-// // 更新返佣明细中状态
- agentReturnDao.updateAgentReturnStatusByRefererId(AgentReturnEntity.IS_RETURN_Y, refererId);
-// // 插入财务流水记录
- memberAccountMoneyChangeDao.insert(moneyChange);
- }
- }
- }
-}
diff --git a/src/test/java/com/xcong/excoin/SmsTest.java b/src/test/java/com/xcong/excoin/SmsTest.java
deleted file mode 100644
index 8c527e5..0000000
--- a/src/test/java/com/xcong/excoin/SmsTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.xcong.excoin;
-
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.text.UnicodeUtil;
-import cn.hutool.core.util.XmlUtil;
-import cn.hutool.http.HttpUtil;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import java.util.Date;
-import java.util.HashMap;
-
-/**
- * @author wzy
- * @date 2020-05-26
- **/
-@SpringBootTest
-public class SmsTest {
-
- public static void main(String[] args) {
- String url = "http://www.qf106.com/sms.aspx";
- HashMap<String,Object> param = new HashMap<>();
- param.put("userid", "16580");
- param.put("account", "Biue");
- param.put("password", "123456");
- param.put("mobile", "15773002834");
- param.put("content", "这是测试");
- param.put("sendTime", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));
- param.put("action", "send");
- param.put("checkcontent", 0);
- param.put("taskName", "验证码");
- param.put("countnumber", 1);
- param.put("mobilenumber", 1);
- param.put("telephonenumber", 0);
-
- String response = HttpUtil.post(url, param);
- System.out.println(response);
- System.out.println(XmlUtil.xmlToMap(response).get("returnstatus"));
- }
-
-}
diff --git a/src/test/java/com/xcong/excoin/SymbolsTest.java b/src/test/java/com/xcong/excoin/SymbolsTest.java
deleted file mode 100644
index 7cdd104..0000000
--- a/src/test/java/com/xcong/excoin/SymbolsTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package com.xcong.excoin;
-
-import cn.hutool.core.collection.CollUtil;
-import com.xcong.excoin.common.LoginUserUtils;
-import com.xcong.excoin.common.enumerates.CoinTypeEnum;
-import com.xcong.excoin.common.system.service.CommonService;
-import com.xcong.excoin.modules.contract.dao.ContractEntrustOrderDao;
-import com.xcong.excoin.modules.contract.dao.ContractHoldOrderDao;
-import com.xcong.excoin.modules.contract.dao.ContractOrderDao;
-import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
-import com.xcong.excoin.modules.contract.service.ContractHoldOrderService;
-import com.xcong.excoin.modules.member.dao.MemberDao;
-import com.xcong.excoin.modules.member.dao.MemberLevelRateDao;
-import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
-import com.xcong.excoin.modules.member.entity.MemberEntity;
-import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
-import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
-import com.xcong.excoin.modules.symbols.service.SymbolsService;
-import com.xcong.excoin.rabbit.producer.OrderProducer;
-import com.xcong.excoin.utils.CacheSettingUtils;
-import com.xcong.excoin.utils.CalculateUtil;
-import com.xcong.excoin.utils.CoinTypeConvert;
-import com.xcong.excoin.utils.RedisUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-26
- **/
-@Slf4j
-@SpringBootTest
-public class SymbolsTest {
-
- @Resource
- private ContractHoldOrderDao contractHoldOrderDao;
-
- @Resource
- private ContractOrderDao contractOrderDao;
-
- @Resource
- private ContractEntrustOrderDao contractEntrustOrderDao;
-
- @Resource
- private CommonService commonService;
-
- @Resource
- private MemberWalletContractDao memberWalletContractDao;
-
- @Resource
- private MemberLevelRateDao memberLevelRateDao;
-
- @Resource
- private CacheSettingUtils cacheSettingUtils;
-
- @Resource
- private RedisUtils redisUtils;
-
- @Resource
- private OrderProducer producer;
-
- @Resource
- private MemberDao memberDao;
-
- @Resource
- private SymbolsService symbolsService;
-
- @Test
- public void symbolsTest() {
- symbolsService.updateSymbolsKine("1min");
- }
-
- @Test
- public void moneyTest() {
- MemberEntity memberEntity = memberDao.selectById(11L);
- PlatformTradeSettingEntity tradeSetting = cacheSettingUtils.getTradeSetting();
-
- List<ContractHoldOrderEntity> holdOrderEntities = contractHoldOrderDao.selectHoldOrderListByMemberId(memberEntity.getId());
-
- BigDecimal beUsedBondAmount = BigDecimal.ZERO;
- // 总盈利
- BigDecimal totalProfitOrLess = BigDecimal.ZERO;
- if (CollUtil.isNotEmpty(holdOrderEntities)) {
- for (ContractHoldOrderEntity holdOrderEntity : holdOrderEntities) {
- // 获取最新价
- BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(holdOrderEntity.getSymbol())));
- BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(holdOrderEntity.getSymbol());
- beUsedBondAmount = beUsedBondAmount.add(holdOrderEntity.getBondAmount());
-
- // 单个订单盈利
- BigDecimal profitOrLess = BigDecimal.ZERO;
- // 开多
- if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
- profitOrLess = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt())).multiply(lotNumber);
- // 开空
- } else {
- profitOrLess = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt())).multiply(lotNumber);
- }
-
- if (MemberEntity.IS_PROFIT_Y == memberEntity.getIsProfit()) {
- if (profitOrLess.compareTo(BigDecimal.ZERO) > 0) {
- profitOrLess = profitOrLess.multiply(BigDecimal.ONE.subtract(tradeSetting.getForceParam()));
- } else {
- profitOrLess = profitOrLess.multiply(BigDecimal.ONE.add(tradeSetting.getForceParam()));
- }
- }
-
- totalProfitOrLess = totalProfitOrLess.add(profitOrLess);
- }
- }
- MemberWalletContractEntity walletContractEntity = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), CoinTypeEnum.USDT.name());
-
- log.info("--->{}", walletContractEntity.getTotalBalance());
- log.info("----->{}", totalProfitOrLess);
-
- }
-
- @Test
- public void forceTest() {
- ContractHoldOrderEntity hold = contractHoldOrderDao.selectById(28284L);
- MemberEntity memberEntity = memberDao.selectById(6L);
- BigDecimal forceSetPrice = CalculateUtil.getForceSetPrice(hold.getBondAmount(), hold.getOpeningPrice(), hold.getSymbolCnt(), hold.getSymbolSku(), hold.getOpeningType(), memberEntity);
- System.out.println(forceSetPrice);
- }
-
- @Resource
- private ContractHoldOrderService contractHoldOrderService;
-
- @Test
- public void holdAmountTest() {
- try {
- contractHoldOrderService.calHoldFeeAmountForBondAmount();
- } catch (Exception e) {
- log.info("-->", e);
- }
- }
-}
diff --git a/src/test/java/com/xcong/excoin/mapper/Car.java b/src/test/java/com/xcong/excoin/mapper/Car.java
deleted file mode 100644
index b432912..0000000
--- a/src/test/java/com/xcong/excoin/mapper/Car.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xcong.excoin.mapper;
-
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * @author wzy
- * @date 2020-05-05 11:00
- **/
-@Data
-public class Car {
- private String name;
-
- private String color;
-
- private Date createTime;
-}
diff --git a/src/test/java/com/xcong/excoin/mapper/CarDto.java b/src/test/java/com/xcong/excoin/mapper/CarDto.java
deleted file mode 100644
index 3d19f26..0000000
--- a/src/test/java/com/xcong/excoin/mapper/CarDto.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.mapper;
-
-import lombok.Data;
-
-/**
- * @author wzy
- * @date 2020-05-05 11:00
- **/
-@Data
-public class CarDto {
- private String name;
-
- private String color;
-
- private String createTime;
-}
diff --git a/src/test/java/com/xcong/excoin/mapper/CarEntity.java b/src/test/java/com/xcong/excoin/mapper/CarEntity.java
deleted file mode 100644
index f92675c..0000000
--- a/src/test/java/com/xcong/excoin/mapper/CarEntity.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcong.excoin.mapper;
-
-import lombok.Data;
-
-/**
- * @author wzy
- * @date 2020-05-05 15:04
- **/
-@Data
-public class CarEntity {
- private String userName;
-
- private String userColor;
-
- private String time;
-}
diff --git a/src/test/java/com/xcong/excoin/mapper/CarMapper.java b/src/test/java/com/xcong/excoin/mapper/CarMapper.java
deleted file mode 100644
index 3d27cc1..0000000
--- a/src/test/java/com/xcong/excoin/mapper/CarMapper.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.xcong.excoin.mapper;
-
-import org.mapstruct.*;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-05 11:00
- **/
-@Mapper
-public abstract class CarMapper {
- public static final CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
-
- @Mapping(source = "createTime", target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
- public abstract CarDto carToCarDto(Car car);
-
- @InheritInverseConfiguration
- @Mapping(target = "name", ignore = true)
- public abstract Car carDtoToCar(CarDto carDto);
-
- @Named("useMe1")
- @Mapping(source = "name", target = "userName")
- @Mapping(source = "color", target = "userColor")
- @Mapping(source = "createTime", target = "time", dateFormat = "yyyy-MM-dd HH:mm:ss")
- public abstract CarEntity carToCarEntity(Car car);
-
- @Mapping(source = "name", target = "userName")
- @Mapping(source = "color", target = "userColor")
- public abstract CarEntity carToCarEntityList(Car car);
-
- @InheritInverseConfiguration(name = "carToCarEntity")
- public abstract Car carEntityToCar(CarEntity carEntity);
-
-
- @Named("useMe")
- @InheritInverseConfiguration(name = "carToCarEntityList")
- public abstract Car carEntityToCar1(CarEntity carEntity);
-
- @IterableMapping(qualifiedByName = "useMe1")
- public abstract List<CarEntity> carEntitiesToCarList(List<Car> list);
-
- @IterableMapping(qualifiedByName = "useMe")
- public abstract List<Car> carsToCarEntities(List<CarEntity> list);
-}
diff --git a/src/test/java/com/xcong/excoin/mapper/MapStructMapper.java b/src/test/java/com/xcong/excoin/mapper/MapStructMapper.java
deleted file mode 100644
index 08beda8..0000000
--- a/src/test/java/com/xcong/excoin/mapper/MapStructMapper.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.xcong.excoin.mapper;
-
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import com.xcong.excoin.modules.coin.entity.OrderCoinsDealEntity;
-import com.xcong.excoin.modules.coin.mapper.OrderWalletCoinDealMapper;
-import com.xcong.excoin.modules.coin.parameter.vo.OrderWalletCoinDealVo;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * @author wzy
- * @date 2020-05-05 10:59
- **/
-@Slf4j
-@SpringBootTest
-public class MapStructMapper {
-
-
- @Test
- public void mapperConvert() {
- Car car = new Car();
- car.setColor("123");
- car.setName("321");
- car.setCreateTime(new Date());
- CarDto carDto = CarMapper.INSTANCE.carToCarDto(car);
- log.info(carDto.toString());
- }
-
- @Test
- public void carDtoToCarConvert() {
- CarDto carDto = new CarDto();
- carDto.setName("dddd");
- carDto.setColor("aaaa");
- carDto.setCreateTime("2020-12-12 12:22:22");
- Car car = CarMapper.INSTANCE.carDtoToCar(carDto);
- log.info(car.toString());
- }
-
- @Test
- public void carToCarEntity() {
- Car car = new Car();
- car.setName("123");
- car.setColor("33333");
- car.setCreateTime(new Date());
- CarEntity carEntity = CarMapper.INSTANCE.carToCarEntity(car);
- log.info(carEntity.toString());
- }
-
- @Test
- public void carEntityToCar() {
- CarEntity carEntity = new CarEntity();
- carEntity.setUserName("11111");
- carEntity.setUserColor("33333");
- carEntity.setTime("2020-12-12 12:22:22");
- Car car = CarMapper.INSTANCE.carEntityToCar(carEntity);
- log.info(car.toString());
- }
-
- @Test
- public void carEntityListToCarList() {
- List<CarEntity> list = new ArrayList<>();
- for (int i = 0; i < 4; i++) {
- CarEntity carEntity = new CarEntity();
- carEntity.setTime("2020-12-12 12:22:33");
- carEntity.setUserName("zs" + i);
- carEntity.setUserColor("red" + i);
- list.add(carEntity);
- }
- List<Car> cars = CarMapper.INSTANCE.carsToCarEntities(list);
- log.info(cars.toString());
- }
-
- @Test
- public void carToCarEntityList() {
- List<Car> list = new ArrayList<>();
- for (int i = 0; i < 4; i++) {
- Car car = new Car();
- car.setName("zs"+i);
- car.setColor("black" + i);
- car.setCreateTime(new Date());
- list.add(car);
- }
-
- List<CarEntity> entities = CarMapper.INSTANCE.carEntitiesToCarList(list);
- log.info(entities.toString());
- }
-
- @Test
- public void walletCoinTest() {
- OrderCoinsDealEntity orderCoinsDealEntity = new OrderCoinsDealEntity();
- orderCoinsDealEntity.setMemberId(1L);
- orderCoinsDealEntity.setOrderNo("123445");
- OrderWalletCoinDealVo entityToVo = OrderWalletCoinDealMapper.INSTANCE.entityToVoOrder(orderCoinsDealEntity);
- System.out.println(entityToVo);
- }
-
-}
diff --git a/src/test/java/com/xcong/excoin/modules/newPrice/OkxWebSocketClientTest.java b/src/test/java/com/xcong/excoin/modules/newPrice/OkxWebSocketClientTest.java
deleted file mode 100644
index 0aac99d..0000000
--- a/src/test/java/com/xcong/excoin/modules/newPrice/OkxWebSocketClientTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.xcong.excoin.modules.newPrice;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-public class OkxWebSocketClientTest {
-
- @Test
- public void testOkxWebSocketConnection() throws InterruptedException {
- // 给足够的时间观察WebSocket连接和数据接收
- Thread.sleep(60000); // 运行1分钟
- }
-}
\ No newline at end of file
--
Gitblit v1.9.1