1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
| /** * <pre> * 1. 交易对配置文件工厂,目前实现从HUOBI.txt文件中读取; * 2. 可以在jar包所在目录下创建config目录,将配置文件放入config目录下,程序会自动读取; * </pre> */ @Slf4j public class SymbolLedgerFactory {
public static final String SYMBOL_HUOBI_BOOKS_FILE = "HUOBI.txt";
public static final String SYMBOL_XT_BOOKS_FILE = "XT.txt";
public static final String SYMBOL_BINANCE_BOOKS_FILE = "BIAN.txt";
public static final String SYMBOL_MEXC_BOOKS_FILE = "MXCAll.txt";
public static final String SYMBOL_GATEIO_BOOKS_FILE = "GATEIO.txt";
public static final String SYMBOL_KUCOIN_BOOKS_FILE = "KUCOIN.txt";
/** * TODO 从文件中读取交易对配置,目前只解析部分字段;有需要实时更新的字段到时候从服务器上实时拉取; * swapStableCoinContractAdd 字段配置决定了与交易所的对的匹配; * * @param symbolBooksFile * @param swapConfig * @return */ private static SymbolLedger create(String symbolBooksFile, SwapConfig swapConfig) { Preconditions.checkArgument(swapConfig != null); JSONArray jsonArray = getJsonArrayByFile(symbolBooksFile); SymbolLedger symbolLedger = new SymbolLedger(); for (int i = 0; i < jsonArray.size(); i++) { JSONObject item = jsonArray.getJSONObject(i);
// continue to parse the json object if (Strings.isNullOrEmpty(item.getString("swapContract")) || item.getString("swapStableCoinContract") .equalsIgnoreCase("cake")) { continue; }
SymbolPairConfig symbolPairConfig = new SymbolPairConfig(); symbolPairConfig.setBaseCurrency(item.getString("swapCoinContract"));
int chainId = item.getInteger("chainId") != null ? item.getInteger("chainId") : NetworkEnum.BSC.getChainId(); String stableName = SymbolTokenHelper.getTokenInfoByAddressReturnSymbol(chainId, item.getString("swapStableCoinContractAdd"));
symbolPairConfig.setQuoteCurrency(Currency.USDT.getCurrencyCode()); // symbolPairConfig.setSymbol(symbolPairConfig.getBaseCurrency() + "/" + symbolPairConfig.getQuoteCurrency());
// 链上交易对和cex交易对 分别存储,交易所对,目前统一使用usdt CenterSymbolInfo centerSymbolInfo = new CenterSymbolInfo(); centerSymbolInfo.setBaseCurrency(symbolPairConfig.getBaseCurrency()); centerSymbolInfo.setQuoteCurrency(Currency.USDT.getCurrencyCode()); centerSymbolInfo.setCexMaxOrderForUSDT(item.getBigDecimal("maxOrderForUsdt") == null ? swapConfig.getGlobalMaxOrderForUsdt() : item.getBigDecimal("maxOrderForUsdt")); centerSymbolInfo.setCexMinOrderForUSDT(item.getBigDecimal("minOrderForUsdt") == null ? swapConfig.getGlobalMinOrderForUsdt() : item.getBigDecimal("minOrderForUsdt")); centerSymbolInfo.getAskPosition() .set(item.getInteger("askPosition") == null || item.getInteger("askPosition") == 0 ? 3 : item.getInteger("askPosition"));
symbolPairConfig.setCenterSymbolInfo(centerSymbolInfo);
// 设置去中心化交易所配置信息; DecenterSymbolInfo decenterSymbolInfo = new DecenterSymbolInfo(); decenterSymbolInfo.setBaseCurrency(symbolPairConfig.getBaseCurrency()) .setQuoteCurrency(stableName == null ? CoinEnum.getCoin(item.getString("swapStableCoinContractAdd")) .name() : stableName) .setMiddleCurrency(item.getString("swapMiddleCoinContract")) .setDexName(item.getString("dex_name")) .setDexProtocolVersion(item.getString("liquidity_type")) // 链id .setChainIds(Set.of(chainId)) .setStableCoinContractAddress(item.getString("swapStableCoinContractAdd")) .setMiddleCoinContractAddress(item.getString("swapMiddleCoinContractAdd")) .setTradeCoinContractAddress(item.getString("swapCoinContractAdd")) .setSwapContractAddress(item.getString("swapContract")) .setBurnFee(item.getBigDecimal("burn")) .setBuyTax(item.getBigDecimal("buyTax"))// 买入税率 .setSellTax(item.getBigDecimal("sellTax"))//卖出税率 // .setSellTax(item.getBigDecimal("burn"))// 卖出税率, 老的配置文件中就是sellTax .setDexBuySlipPoint(item.getBigDecimal("dexSlipPoint") .add(swapConfig.getGlobalDexSlipPoint())) .setStableCoinDecimals(item.getIntValue("stableCoinDecimals")) .setTradeCoinDecimals(item.getIntValue("coinDecimals")) .setMiddleCoinDecimals(item.getIntValue("middleCoinDecimals")) .setMethod(item.getString("method")) .setBuyPosition(item.getIntValue("currentDepthPosition")) .setReplyPro(item.getBigDecimal("replyPro")) // 反向利润放大的比例 .setDepthPro(item.getBigDecimal("depthPro")) // 反向深度缩小的比例 .setV3LoopContractAddress(item.getString("lpAdd")) // v3 的loopAddress .setV3Fee(item.getString("feev3")) // v3 的fee .setDexMaxOrderForUSDT(item.getBigDecimal("dexMax") == null ? swapConfig.getGlobalMaxOrderForUsdt() : item.getBigDecimal("dexMax")) // 反向最大下单量 .setDexMinOrderForUSDT(item.getBigDecimal("dexMin") == null ? swapConfig.getGlobalMinOrderForUsdt() : item.getBigDecimal("dexMin"));// 反向最小下单量
decenterSymbolInfo.setExtensionDexHandlerConfig(new ExtensionDexHandlerConfig(item));
decenterSymbolInfo.init(); symbolPairConfig.setDecenterSymbolInfo(decenterSymbolInfo); symbolPairConfig.set_rawJson(item);
symbolLedger.put(symbolPairConfig); } return symbolLedger; }
private static JSONArray getJsonArrayByFile(String symbolHuobiBooksFile) { File configFile = PathUtil.stairsLoad(symbolHuobiBooksFile, "config");
try {
if (configFile == null) { log.warn("Not fount SymbolBook config file.{}", symbolHuobiBooksFile); String tempPath = System.getProperty("java.io.tmpdir") + System.currentTimeMillis(); String tempFile = Paths.get(tempPath, File.separator, symbolHuobiBooksFile) .toString(); Resource resource = new ClassPathResource(symbolHuobiBooksFile); InputStream initialStream = resource.getInputStream(); byte[] buffer = new byte[initialStream.available()]; initialStream.read(buffer); configFile = new File(tempFile); configFile.getParentFile() .mkdirs(); Files.write(buffer, configFile); log.info("Loading default SymbolBook config file from classpath: {} ", resource.getURL()); }
String jsonContext = Joiner.on("") .join(Files.readLines(configFile, Charsets.UTF_8));
if (JSON.isValidArray(jsonContext)) { return JSON.parseObject(jsonContext, JSONArray.class); }
} catch (Exception e) { log.error(e.getMessage(), e); throw new SwapException("SymbolBook config loading failed.");
} return new JSONArray(); }
public static SymbolLedger createXT(SwapConfig swapConfig) { return create(SYMBOL_XT_BOOKS_FILE, swapConfig); }
public static SymbolLedger createHuoBi() { return create(SYMBOL_HUOBI_BOOKS_FILE, new SwapConfig()); }
public static SymbolLedger createGateio() { return create(SYMBOL_GATEIO_BOOKS_FILE, new SwapConfig()); }
public static SymbolLedger createGateio(SwapConfig swapConfig) { return create(SYMBOL_GATEIO_BOOKS_FILE, swapConfig); }
public static SymbolLedger createKucoin(SwapConfig swapConfig) { return create(SYMBOL_KUCOIN_BOOKS_FILE, swapConfig); }
public static SymbolLedger createOKex() { return create(SYMBOL_HUOBI_BOOKS_FILE, new SwapConfig()); }
public static SymbolLedger createOKex(SwapConfig swapConfig) { return create(SYMBOL_HUOBI_BOOKS_FILE, swapConfig); }
public static SymbolLedger createHuoBi(SwapConfig swapConfig) { return create(SYMBOL_HUOBI_BOOKS_FILE, swapConfig); }
public static SymbolLedger createBinance(SwapConfig swapConfig) { return create(SYMBOL_BINANCE_BOOKS_FILE, swapConfig); }
public static SymbolLedger createMEXC(SwapConfig swapConfig) { return create(SYMBOL_MEXC_BOOKS_FILE, swapConfig); }
/** * 将配置文件内容刷入db * 外部通过SwapControlHolder 来对状态进行控制和判断 * * @param symbolLedger * @param exchangeType * @param isMonitor 开关用来控制swapSymbolPairConfigRecord 记录默认是监听状态还是, 非监听状态, * 首次程序启动的时候是非监听的,需要web端显式的开启,后续job中动态调整默认都是监听状态的 */ public static void flushToDb(SymbolLedger symbolLedger, ExchangeType exchangeType, boolean isMonitor) { if (symbolLedger.isMemoryMode()) { return; } SwapSymbolPairConfigRecordRepository res = SpringUtil.getBean(SwapSymbolPairConfigRecordRepository.class); res.deleteAllByExchangeType(exchangeType); res.flush(); List<SwapSymbolPairConfigRecord> all = Lists.newArrayList(); symbolLedger.getSymbolPairConfigs().forEach(symbolPairConfig -> { SwapSymbolPairConfigRecord swapSymbolPairConfigRecord = null; if (isMonitor) { swapSymbolPairConfigRecord = SwapSymbolPairConfigRecord.createLoadMonitor(symbolPairConfig, exchangeType); SwapControlManager.putItem(exchangeType, symbolPairConfig.getUniDexIdentify(), swapSymbolPairConfigRecord); } else { swapSymbolPairConfigRecord = SwapSymbolPairConfigRecord.createUnMonitor(symbolPairConfig, exchangeType); SwapControlManager.putItem(exchangeType, symbolPairConfig.getUniDexIdentify(), swapSymbolPairConfigRecord); } all.add(swapSymbolPairConfigRecord); }); res.saveAllAndFlush(all); log.info("Load config from config file, Flush to db is ok ! Record size is :{} ", all.size()); }
/** * 增量更新配置文件 * 1. 数据库中载入当前交易所币配置 * 2. 从内存中获取当前交易所币配置 * 3. 比较数据库中不在内存的配置,更新状态 * 4. 将关闭的币种组装日志打印出来 */ public static void incrementalUpdate(SymbolLedger symbolLedger, ExchangeType exchangeType) { if (symbolLedger.isMemoryMode()) { return; } SwapSymbolPairConfigRecordRepository res = SpringUtil.getBean(SwapSymbolPairConfigRecordRepository.class); List<SwapSymbolPairConfigRecord> all = res.findAllByExchangeType(exchangeType);
String changeCurrency = ""; int closeCount = 0; for (SwapSymbolPairConfigRecord swapSymbolPairConfigRecord : all) { String symbol = swapSymbolPairConfigRecord.getSymbol(); if (symbolLedger.getSymbolPairConfig(symbol.split("/")[0], symbol.split("/")[1]) == null) { swapSymbolPairConfigRecord.setMonitorStatus(SwapSymbolPairConfigRecord.MonitorStatus.UNMONITOR);
changeCurrency += symbol + ","; closeCount++; } } res.saveAllAndFlush(all);
String msg = Utils.format("{} 交易所内存币本配置已过滤,总数:{} 关闭数量:{} 关闭币种:{}", exchangeType, all.size(), closeCount, changeCurrency); log.info(msg); SwapMessageSender.sendMessage(exchangeType, msg); log.info("Incremental update config from config file, Flush to db is ok ! Record size is :{} ", all.size());
}
|