package com.yami.trading.huobi.hobi.internal; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import com.yami.trading.bean.cms.Infomation; import com.yami.trading.bean.data.domain.*; import com.yami.trading.bean.data.respDto.TradeTickResp; import com.yami.trading.bean.item.domain.Item; import com.yami.trading.common.util.RedisUtil; import com.yami.trading.common.util.StringUtils; import com.yami.trading.common.util.UTCDateUtils; import com.yami.trading.huobi.data.DataCache; import com.yami.trading.huobi.data.internal.DepthTimeObject; import com.yami.trading.huobi.data.internal.KlineConstant; import com.yami.trading.huobi.data.internal.KlineService; import com.yami.trading.huobi.data.internal.TradeTimeObject; import com.yami.trading.huobi.data.model.AlltickBatchKlineResult; import com.yami.trading.huobi.data.model.AlltickNewPriceResult; import com.yami.trading.huobi.data.model.AllticktradeResult; import com.yami.trading.huobi.hobi.HobiDataService; import com.yami.trading.huobi.hobi.constant.AllticktradeMadeOptions; import com.yami.trading.huobi.hobi.http.HttpHelper; import com.yami.trading.huobi.hobi.http.HttpMethodType; import com.yami.trading.service.cms.InfomationService; import com.yami.trading.service.item.ItemService; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; /** * 新浪k线图采集 */ @Component public class XinLangDataServiceImpl { // https://vip.stock.finance.sina.com.cn/forex/api/jsonp.php/var%20_fx_seurusd_1_1688818651726=/NewForexService.getMinKline?symbol=fx_seurusd&scale=1&datalen=2000 public final static String klineUrl = "https://vip.stock.finance.sina.com.cn/forex/api/jsonp.php/var%20_fx_s{1}_1_{3}=/NewForexService.getMinKline?symbol=fx_s{1}&scale={2}&datalen=2000"; public final static String klineDay = "https://vip.stock.finance.sina.com.cn/forex/api/jsonp.php/var%20_fx_s{1}{2}=/NewForexService.getDayKLine?symbol=fx_s{1}&_={2}"; /** * live */ // public final static String live = "https://hq.sinajs.cn/rn={1}list={2}";//todo 要调整 public final static String live = "https://hq.sinajs.cn/etag.php?_={1}&list={2}";//todo 要调整 public final static String live_tick = "https://quote.alltick.io/quote-b-api/kline?token={1}&query={2}"; private static Logger logger = LoggerFactory.getLogger(XinLangDataServiceImpl.class); @Autowired private KlineService klineService; @Autowired private ItemService itemService; @Value("${alltick.trade-tick}") private String tradeTick; @Value("${alltick.batch-kline}") private String batchKline; public static void main(String[] args) { XinLangDataServiceImpl service = new XinLangDataServiceImpl(); List usdsgd = service.realtimeSingle("USDJPY"); for (Realtime re : usdsgd) { System.out.println(JSONObject.toJSONString(re)); } // List sz300750 = service.buildOneYearPeriod("AAPL"); // System.out.println(sz300750.size()); // List eurusd = service.getTimeseriesByPeriodOneDay("EURUSD"); // System.out.println(JSONObject.toJSONString(eurusd)); } public Map createRequest(List strings) { Map requestData = new HashMap<>(); Map data = new HashMap<>(); List> dataList = new ArrayList<>(); for (String symbolCode : strings) { for (int i = 1; i <= 3; i++) { Map dataItem = new HashMap<>(); dataItem.put("code", symbolCode); dataItem.put("kline_type", i); dataItem.put("kline_timestamp_end", 0); dataItem.put("query_kline_num", 1); dataList.add(dataItem); } } data.put("data_list", dataList); requestData.put("trace", UUID.randomUUID().toString()); requestData.put("data", data); return requestData; } public Map createRequestTick(List strings) { // 创建 JSON 对象 JSONObject response = new JSONObject(); response.put("trace", UUID.randomUUID().toString()); // 创建数据部分 JSONObject dataObject = new JSONObject(); JSONArray symbolList = new JSONArray(); // 构造符号列表 for (String code : strings) { JSONObject symbol = new JSONObject(); symbol.put("code", code); symbolList.add(symbol); } dataObject.put("symbol_list", symbolList); response.put("data", dataObject); return response; } public Map createRequestZdf(String symbolCode) { JSONObject json = new JSONObject(); json.put("trace", UUID.randomUUID().toString()); JSONObject data = new JSONObject(); data.put("code", symbolCode); data.put("kline_type", 8); data.put("kline_timestamp_end", 0); data.put("query_kline_num", 2); json.put("data", data); return json; } /** * 获取原始的K线图数据 * * @param symbol * @param cookie * @return */ public String getRawTimeseriesByMinute(String symbol, String cookie) { long nowTs = System.currentTimeMillis(); long begin = nowTs; String url = StrUtil.format(klineUrl, symbol, begin, "1m"); return HttpHelper.sendGetHttp(url, null, cookie); } public List realtimeNewPrice(String symbols,List realtimes) { //获取最新价 try{ List strings = Arrays.asList(symbols.split(",")); Map requestDataTick = createRequestTick(strings); String url = tradeTick.replace("{1}", URLEncoder.encode(requestDataTick.toString(), "UTF-8")); HttpGet request = new HttpGet(url); HttpResponse response = HttpHelper.getHttpclient().execute(request); String resultTickStr = HttpHelper.responseProc(response); JSONObject resultJsonTick = JSON.parseObject(resultTickStr); if(null == resultJsonTick || 200 != resultJsonTick.getInteger("ret")){ logger.error("数据,返回:{} ", resultJsonTick); } JSONObject tempdataTick = resultJsonTick.getJSONObject("data"); JSONArray dataArrayTick = tempdataTick.getJSONArray("tick_list"); if (dataArrayTick.size() > 0) { List alltickNewPriceResults = JSONObject.parseArray(JSONObject.toJSONString(dataArrayTick), AlltickNewPriceResult.class); for (AlltickNewPriceResult tickNewPrice : alltickNewPriceResults) { for (Realtime realtime : realtimes){ if(tickNewPrice.getCode().equals(realtime.getName())){ realtime.setCloseOld(realtime.getClose()); // realtime.setClose(new BigDecimal(tickNewPrice.getPrice())); // realtime.setVolume(new BigDecimal(tickNewPrice.getVolume())); } // Item bySymbol = itemService.findBySymbol(realtime.getSymbol()); // if(null != bySymbol.getYesterdayLastPrice() && bySymbol.getYesterdayLastPrice().compareTo(BigDecimal.ZERO) != 0){ // BigDecimal changePercent = (realtime.getClose().subtract(bySymbol.getYesterdayLastPrice())) // .divide(bySymbol.getYesterdayLastPrice(), 5, RoundingMode.HALF_UP) // 精确到4位小数 // .multiply(new BigDecimal("100").setScale(2)).setScale(4,RoundingMode.HALF_UP); // 乘以100得到百分比 // realtime.setChangeRatioStr(changePercent); // } } } } // Map requestData = createRequest(strings); // String resultStr = HttpHelper.sendPostRequest(batchKline,requestData); // JSONObject resultJson = JSON.parseObject(resultStr); // if(null == resultJson || 200 != resultJson.getInteger("ret")){ // logger.error("数据,返回:{} ", resultJson); // } // JSONObject tempdata = resultJson.getJSONObject("data"); // JSONArray dataArray = tempdata.getJSONArray("kline_list"); // if (dataArray.size() > 0) { // List batchKlines = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AlltickBatchKlineResult.class); // for (AlltickBatchKlineResult batchKline : batchKlines) { // for (AllticktradeResult result : batchKline.getKline_data()){ // for (Realtime realtime : list){ // if(realtime.getSymbol().equals(batchKline.getCode())){ // int decimal = itemService.getDecimal(realtime.getSymbol()); // realtime.setOpen(result.getOpen_price().setScale(decimal, RoundingMode.HALF_UP)); // realtime.setHigh(result.getHigh_price().setScale(decimal, RoundingMode.HALF_UP)); // realtime.setLow(result.getLow_price().setScale(decimal, RoundingMode.HALF_UP)); // realtime.setClose(result.getClose_price().setScale(decimal, RoundingMode.HALF_UP)); //// realtime.setAmount(tickNewPrice.getPrice().multiply(tickNewPrice.getVolume()).setScale(item.getDecimals(), RoundingMode.HALF_UP)); //// realtime.setVolume(tickNewPrice.getVolume()); // } // } // } // } // } } catch (Exception e){ logger.error("error", e); } return realtimes; } public List realtimeSingle(String symbols) { List list = new ArrayList(); try { List strings = Arrays.asList(symbols.split(",")); Map requestDataTick = createRequestTick(strings); String url = tradeTick.replace("{1}", URLEncoder.encode(requestDataTick.toString(), "UTF-8")); HttpGet request = new HttpGet(url); HttpResponse response = HttpHelper.getHttpclient().execute(request); String resultTickStr = HttpHelper.responseProc(response); JSONObject resultJsonTick = JSON.parseObject(resultTickStr); if(null == resultJsonTick || 200 != resultJsonTick.getInteger("ret")){ logger.error("数据,返回:{} ", resultJsonTick); } JSONObject tempdataTick = resultJsonTick.getJSONObject("data"); JSONArray dataArrayTick = tempdataTick.getJSONArray("tick_list"); if (dataArrayTick.size() > 0) { List alltickNewPriceResults = JSONObject.parseArray(JSONObject.toJSONString(dataArrayTick), AlltickNewPriceResult.class); for (AlltickNewPriceResult tickNewPrice : alltickNewPriceResults) { Realtime realtime = new Realtime(); Item item = itemService.findBySymbol(tickNewPrice.getCode()); realtime.setSymbol(tickNewPrice.getCode()); realtime.setTs(Long.parseLong(tickNewPrice.getTickTime())); realtime.setName(tickNewPrice.getCode()); realtime.setClose(tickNewPrice.getPrice().setScale(item.getDecimals(), RoundingMode.HALF_UP)); // //涨跌幅 = (当天收盘价 - 前一日收盘价) / 前一日收盘价 * 100% // if(null != item.getYesterdayLastPrice() && item.getYesterdayLastPrice().compareTo(BigDecimal.ZERO) != 0){ // BigDecimal changePercent = (realtime.getClose().subtract(item.getYesterdayLastPrice())) // .divide(item.getYesterdayLastPrice(), 5, RoundingMode.HALF_UP) // 精确到4位小数 // .multiply(new BigDecimal("100").setScale(2)).setScale(4,RoundingMode.HALF_UP); // 乘以100得到百分比 // realtime.setChangeRatioStr(changePercent); // } realtime.setMarketCapital(0L); realtime.setFloatMarketCapital(0L); realtime.setPeForecast(BigDecimal.ZERO); realtime.setVolumeRatio(BigDecimal.ZERO); realtime.setTurnoverRate(BigDecimal.ZERO); Kline kline = klineService.getLast(tickNewPrice.getCode(),Kline.PERIOD_1DAY); if(null != kline){ realtime.setOpen(kline.getOpen().setScale(item.getDecimals(), RoundingMode.HALF_UP)); realtime.setHigh(kline.getHigh().setScale(item.getDecimals(), RoundingMode.HALF_UP)); realtime.setLow(kline.getLow().setScale(item.getDecimals(), RoundingMode.HALF_UP)); realtime.setAmount(kline.getAmount().setScale(item.getDecimals(), RoundingMode.HALF_UP)); realtime.setVolume(kline.getVolume().setScale(item.getDecimals(), RoundingMode.HALF_UP)); }else { realtime.setOpen(BigDecimal.ZERO); realtime.setHigh(BigDecimal.ZERO); realtime.setLow(BigDecimal.ZERO); realtime.setAmount(BigDecimal.ZERO); realtime.setVolume(BigDecimal.ZERO); } list.add(realtime); } } } catch (Exception e) { logger.error("error", e); } return list; } public List realtime(String symbols) { List realtimeList = realtimeSingle(symbols); return realtimeList; } /** * 1day 历史数据 : 周期 1年 * 1week,1mon 历史数据 : 周期 5年 * 请求 350次 */ public Map> getDailyWeekMonthHistory(String symbol) { Map> map = new HashMap<>(); List oneDayPeriod = buildOneDayPeriod(symbol); // public List calculateKline(String symbol, int seq, String period, List klineList) ; map.put(Kline.PERIOD_1WEEK, klineService.calculateKline(symbol, 7, Kline.PERIOD_1WEEK, oneDayPeriod)); map.put(Kline.PERIOD_1MON, klineService.calculateKline(symbol, 30, Kline.PERIOD_1MON, oneDayPeriod)); map.put(Kline.PERIOD_1DAY, oneDayPeriod); map.put(Kline.PERIOD_5DAY, klineService.calculateKline(symbol, 5, Kline.PERIOD_5DAY, oneDayPeriod)); map.put(Kline.PERIOD_QUARTER, klineService.calculateKline(symbol, 90, Kline.PERIOD_QUARTER, oneDayPeriod)); map.put(Kline.PERIOD_YEAR, klineService.calculateKline(symbol, 365, Kline.PERIOD_YEAR, oneDayPeriod)); return map; } public List buildOneDayPeriod(String currency) { return getTimeseriesByPeriodOneDay(currency); } /** * 雪球支持120分钟的,讲120分钟的, * Hourly * 4hourly 3月 */ public List getTimeseriesForFourHourly(String currency) { return getTimeseriesByPeriodMinute(currency, 240, Kline.PERIOD_4HOUR); } /** * Hourly * 1hourly 2个小时 */ public List getTimeseriesForTwoHourly(String currency) { return getTimeseriesByPeriodMinute(currency, 120, Kline.PERIOD_2HOUR); } /** * Hourly * 1hourly 1月 */ public List getTimeseriesForOneHourly(String currency) { return getTimeseriesByPeriodMinute(currency, 60, Kline.PERIOD_60MIN); } /** * Minute * 30minute 10天 * 15minute 5天 * 5minute 2天 * 1minute 1天 */ public List getTimeseriesOneMinute(String currency) { return getTimeseriesByPeriodMinute(currency, 1, Kline.PERIOD_1MIN); } /** * Minute * 30minute 10天 * 15minute 5天 * 5minute 2天 * 1minute 1天 */ public List getTimeseriesFiveMinute(String currency) { return getTimeseriesByPeriodMinute(currency, 5, Kline.PERIOD_5MIN); } /** * Minute * 30minute 10天 * 15minute 5天 * 5minute 2天 * 1minute 1天 */ public List getTimeseriesFifteenMinute(String currency) { return getTimeseriesByPeriodMinute(currency, 15, Kline.PERIOD_15MIN); } /** * Minute * 30minute 15 * 15minute 15 * 5minute 15 * 1minute 15 */ public List getTimeseriesThirtyMinute(String currency) { return getTimeseriesByPeriodMinute(currency, 30, Kline.PERIOD_30MIN); } public List getTimeseriesByPeriodMinute(String currency, int scale, String period) { // https://vip.stock.finance.sina.com.cn/forex/api/jsonp.php/var%20_fx_seurusd_1_1688818651726=/NewForexService.getMinKline?symbol=fx_seurusd&scale=1&datalen=2000 long nowTs = System.currentTimeMillis(); String url = klineUrl.replace("{1}", currency.toLowerCase()).replace("{3}", nowTs + "").replace("{2}", scale + ""); List resList = new ArrayList<>(); String json = HttpHelper.sendGetHttp(url, ""); if (!json.contains("(")) { throw new IllegalArgumentException("新浪外汇k线图采集错误"); } json = json.split("\\(")[1].replace(");", ""); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); JSONArray dataArray = JSONObject.parseArray(json); for (Object result : dataArray) { JSONObject data = (JSONObject) result; Kline kline = new Kline(); kline.setSymbol(currency); kline.setPeriod(period); String dateTimeStr = data.getString("d"); // 解析字符串,指定时区为上海 ZonedDateTime dateTime = ZonedDateTime.parse(dateTimeStr, formatter.withZone(ZoneId.of("Asia/Shanghai"))); // 转换成时间戳(毫秒) long ts = dateTime.toInstant().toEpochMilli(); kline.setTs(ts); kline.setOpen(new BigDecimal(data.getString("o"))); kline.setClose(new BigDecimal(data.getString("c"))); kline.setHigh(new BigDecimal(data.getString("h"))); kline.setLow(new BigDecimal(data.getString("l"))); kline.setVolume(BigDecimal.ZERO); kline.setAmount(BigDecimal.ZERO); resList.add(kline); } return resList; } public List getTimeseriesByPeriodOneDay(String currency) { // public final static String klineDay = "https://vip.stock.finance.sina.com.cn/forex/api/jsonp.php/var%20_fx_s{1}{2}=/NewForexService.getDayKLine?symbol=fx_s{1}&_={2}"; LocalDate today = LocalDate.now(); int year = today.getYear(); int month = today.getMonthValue(); int day = today.getDayOfMonth(); String dateStr = year + "_" + month + "_" + day; String url = klineDay.replace("{1}", currency.toLowerCase()).replace("{2}", dateStr); List resList = new ArrayList<>(); String json = HttpHelper.sendGetHttp(url, ""); if (!json.contains("(")) { throw new IllegalArgumentException("新浪外汇k线图采集错误"); } json = json.split("\\(")[1].replace(");", "").replace("\"", ""); DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String[] datas = json.split("\\|"); for (String result : datas) { List ds = Splitter.on(",").omitEmptyStrings().splitToList(result); // 解析字符串,指定时区为上海 Kline kline = new Kline(); kline.setSymbol(currency); kline.setPeriod(Kline.PERIOD_1DAY); LocalDate date = LocalDate.parse(ds.get(0), dateFormatter); // date = 0 , 1是开盘,2是最低。3是最高,4是收盘 // 转换成时间戳(毫秒) long ts = date.atStartOfDay(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli(); kline.setTs(ts); kline.setOpen(new BigDecimal(ds.get(1))); kline.setClose(new BigDecimal(ds.get(4))); kline.setHigh(new BigDecimal(ds.get(3))); kline.setLow(new BigDecimal(ds.get(2))); kline.setVolume(BigDecimal.ZERO); kline.setAmount(BigDecimal.ZERO); resList.add(kline); } return resList; } }