恒易量化-市价马丁策略
2023-05-27 本文已影响0人
往后余生9375
马丁策略
马丁格尔(Martingale)策略其实是一种赌博策略,理论上用这种策略是不会亏钱的,只要你拥有足够多的资金,理论上你将百战百胜
源码(只能运行在恒易量化服务器)
package com.hengyi.strategy.strategy;
import com.alibaba.fastjson.JSONObject;
import com.hengyi.tradesystem.entity.OrderProfit;
import com.hengyi.tradesystem.enums.AlarmLevel;
import com.hengyi.tradesystem.enums.OrderType;
import com.hengyi.tradesystem.strategy.impl.BaseStrategy;
import com.hengyi.tradesystem.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 马丁策略
* 无限加仓,直到盈利
* 限制下单次数 限制下单数量
* 懂得止损
* 下单改为限价单
*
*
* 考虑加入平仓策略
* 1.回调多少卖出
* 2.均价+格子卖出
* 3.双倍仓位 上涨一格卖出
*/
@Slf4j
@Component
@Scope("prototype")
public class MartinStrategy extends BaseStrategy {
private static final String OPEN_MAX_PRICE = "OPEN_MAX_PRICE";
/**
* 策略参数
*/
private BigDecimal highPrice = null;
private BigDecimal lowPrice = null;
private BigDecimal gridSize = null;
private BigDecimal buyMultiple = null;
private BigDecimal buyQty = null;
private BigDecimal maxBuyQty = null;
private BigDecimal lossAmount = null;
private BigDecimal profitVal = null;
private Boolean isProfitAmount = false;
private BigDecimal triggerPrice = null;
private int gridNum = 0;
private int closeType = 0;
@Override
public void init(String accountStrategyId, String instanceId, JSONObject runParams, JSONObject localDict) {
super.init(accountStrategyId, instanceId, runParams,localDict);
if(!checkParams(
"highPrice","lowPrice","gridSize","buyQty","buyMultiple","sendMail","maxBuyQty","lossAmount")){
throw new RuntimeException("运行参数异常");
}
setSendMail(getRunParams().getBoolean("sendMail"));
// 压力价
highPrice = getRunParams().getBigDecimal("highPrice");
// 支撑价格
lowPrice = getRunParams().getBigDecimal("lowPrice");
// 网格大小
gridSize = getRunParams().getBigDecimal("gridSize");
// 加仓倍数
buyMultiple = getRunParams().getBigDecimal("buyMultiple");
// 初始购买数量
buyQty = getRunParams().getBigDecimal("buyQty");
// 网格数量
gridNum = highPrice.subtract(lowPrice).divide(gridSize,0,BigDecimal.ROUND_DOWN).intValue();
// 最大下单数量
maxBuyQty = getRunParams().getBigDecimal("maxBuyQty");
// 最大亏损U平仓
lossAmount = getRunParams().getBigDecimal("lossAmount");
// 平仓方式
closeType = getRunParams().getInteger("closeType");
// 触发价格
if(getRunParams().containsKey("triggerPrice")){
triggerPrice = getRunParams().getBigDecimal("triggerPrice");
if(triggerPrice.compareTo(highPrice) > 0){
throw new RuntimeException("触发价格大于了最高价格");
}
if(triggerPrice.compareTo(lowPrice) < 0){
throw new RuntimeException("触发价格小于了最低价格");
}
}
// 参数校验
if(lossAmount.compareTo(new BigDecimal("0")) <= 0){
throw new RuntimeException("止损金额lossAmount参数设置不正确");
}
if(closeType == 2 && buyMultiple.compareTo(new BigDecimal("2")) < 0){
throw new RuntimeException("该平仓方式购买倍数必须大于等于2");
}
if(closeType == 3 && !getRunParams().containsKey("profitVal")){
throw new RuntimeException("该平仓方式需要填写参数:profitVal");
}
if(lowPrice.compareTo(highPrice) >= 0){
throw new RuntimeException("最低 最高价格设置有误");
}
if(buyQty.compareTo(BigDecimal.ZERO) <= 0){
throw new RuntimeException("购买数量设置有误");
}
if(maxBuyQty.compareTo(buyQty) < 0){
throw new RuntimeException("最大购买数量设置有误");
}
if(buyMultiple.compareTo(BigDecimal.ONE) < 0){
throw new RuntimeException("购买倍数设置有误");
}
// 收益值和收益率
String profitValStr = getRunParams().getString("profitVal");
profitVal = new BigDecimal(profitValStr);
isProfitAmount = !profitValStr.contains("%");
}
@Override
public void pre() {
}
/**
* 获取当前价格所在的网格
* @param m
* @param gridSize
* @param nowPrice
* @param gridNum
* @return
*/
private int getCurrentGrid(BigDecimal m, BigDecimal gridSize,BigDecimal nowPrice,int gridNum){
int num = -1;
for(int i = 0; i<gridNum;i++){
BigDecimal price1 = m.subtract(gridSize.multiply(new BigDecimal(i)));
BigDecimal price2 = m.subtract(gridSize.multiply(new BigDecimal(i + 1)));
if(price1.compareTo(nowPrice) >= 0 && price2.compareTo(nowPrice) < 0){
num = i + 1;
break;
}
}
return num;
}
@Override
public void run(Long currentTime) {
/**
* 支持 盈利多少平仓 支持 盈利百分比平仓 支持网格数平仓
* 支持最大开仓数
* maxBuyQty 最大开仓数量 (加仓到这个数量就停止操作)
* lossAmount 止损数,亏损
* profitAmount 盈利金额
* callbackPrice 回调金额 超过这个金额就平仓
*/
// 当前价格
BigDecimal markPrice = getMarkPrice();
// 当前所属的网格个数(当前价格位于该网格的下面或相等价格)
int currentGrid = getCurrentGrid(highPrice,gridSize,markPrice,gridNum);
log.info("最高价格{} 最低价格{} 网格大小{} 当前在网格{} 当前价格{} 加仓倍数{}",highPrice,lowPrice,gridSize,currentGrid,markPrice,buyMultiple);
// 只在格子里面才下单
if(currentGrid != -1) {
// 如果设置了触发价格 那么第一次开仓需要判断当前标记价格
if(!localDict.containsKey("minOpenGrid") && triggerPrice != null && triggerPrice.compareTo(markPrice) <= 0){
return;
}
openOrder(currentGrid,markPrice);
}
// 平仓 止损
if(hasOpenOrder(true) && closeType > 0){
closeOrder(currentGrid, markPrice);
}
}
/**
* 开仓
* @param currentGrid
*/
private void openOrder(int currentGrid,BigDecimal markPrice){
// 进来网格只要小于中位价格就开单,只要跌处网格就加仓。
// 开单记录开仓的网格数,跌了继续加仓
// 记录第一次开仓
if(!localDict.containsKey("minOpenGrid")) {
Result result = openLong(OrderType.MARKET, String.valueOf(System.currentTimeMillis()), "", "", buyQty.toString());
if (result.getStatus()) {
localDict.put("minOpenGrid", currentGrid);
localDict.put("minOpenPrice",markPrice);
localDict.put("qty",buyQty);
saveLocalDict();
log.info("马丁第一次开单成功,目前开仓网格是:{}",currentGrid);
}
}else {
BigDecimal isFilledQty = getOpenQty(true);
int minOpenGrid = localDict.getInteger("minOpenGrid");
BigDecimal minOpenPrice = localDict.getBigDecimal("minOpenPrice");
if (currentGrid > minOpenGrid && minOpenPrice.subtract(markPrice).compareTo(gridSize) >= 0) {
BigDecimal buy_qty = localDict.getBigDecimal("qty").multiply(buyMultiple);
if(buy_qty.add(isFilledQty).compareTo(maxBuyQty) > 0){
log.info("当前下单数量+已有仓位数量大于了设置的数量,不允许开仓!");
return;
}
Result result = openLong(OrderType.MARKET, String.valueOf(System.currentTimeMillis()), "", "", buy_qty.toString());
if (result.getStatus()) {
localDict.put("minOpenGrid", currentGrid);
localDict.put("minOpenPrice", markPrice);
localDict.put("qty",buy_qty);
saveLocalDict();
log.info("马丁开单成功,目前开仓网格是:{} 购买数量:{}", currentGrid, buy_qty);
}
}
}
}
/**
* 全平仓
* @param currentGrid
*/
private void closeOrder(int currentGrid, BigDecimal markPrice){
OrderProfit orderProfit = getOrderProfit();
if(orderProfit == null){
return;
}
// 计算开仓后达到的盈利最高价
BigDecimal lastNewPrice = null;
BigDecimal nowNewPrice = getNewPrice();
if(localDict.containsKey(OPEN_MAX_PRICE)){
lastNewPrice = localDict.getBigDecimal(OPEN_MAX_PRICE);
if(nowNewPrice.compareTo(lastNewPrice) > 0){
localDict.put(OPEN_MAX_PRICE,nowNewPrice);
}
log.info("当前开仓后的最高价是:{} 现价:{}",lastNewPrice,nowNewPrice);
}else {
lastNewPrice = getNewPrice();
localDict.put(OPEN_MAX_PRICE,lastNewPrice);
}
// 止损
if(orderProfit.getProfitValue().compareTo(lossAmount.multiply(new BigDecimal("-1"))) <= 0){
closePosition();
localDict.clear();
saveLocalDict();
alarm("止损平仓","亏损大于了设置的值", AlarmLevel.INFO);
sleep(2000);
}
if(closeType == 1){
if(nowNewPrice.subtract(gridSize).compareTo(orderProfit.getAvgPrice()) >= 0){
closePosition();
localDict.clear();
saveLocalDict();
alarm("方式1平仓","价格上涨均价上方格子平仓", AlarmLevel.INFO);
sleep(2000);
}
}
// 平仓方式2
if(closeType == 2){
int minOpenGrid = localDict.getInteger("minOpenGrid");
BigDecimal minOpenPrice = localDict.getBigDecimal("minOpenPrice");
if(currentGrid < minOpenGrid){
// 计算预计平单的手续费
BigDecimal closeCommission = orderProfit.getTotalValue().multiply(new BigDecimal("0.0004"));
// 计算预计平仓成本价格
BigDecimal closePrice = orderProfit.getProfitValue().subtract(orderProfit.getCommission()).subtract(closeCommission);
if(minOpenPrice.add(gridSize).compareTo(markPrice) <= 0 && closePrice.compareTo(new BigDecimal("0.05")) > 0){
closePosition();
localDict.clear();
saveLocalDict();
alarm("方式2平仓","达到平仓条件平仓", AlarmLevel.INFO);
sleep(2000);
}
}
}
// 平仓方式3
if(closeType == 3){
if(isProfitAmount) {
if (orderProfit.getProfitValue().compareTo(profitVal) >= 0) {
closePosition();
localDict.clear();
saveLocalDict();
alarm("方式3平仓", "达到设置的止盈金额", AlarmLevel.INFO);
sleep(2000);
}
}else {
if (orderProfit.getProfitRate().compareTo(profitVal) >= 0) {
closePosition();
localDict.clear();
saveLocalDict();
alarm("方式3平仓", "达到设置的止盈率", AlarmLevel.INFO);
sleep(2000);
}
}
}
}
@Override
public void post() {
}
@Override
public void destroy() {
log.info("策略结束,销毁中");
}
}