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.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.common.util.ApplicationUtil; import com.yami.trading.common.util.RedisUtil; import com.yami.trading.huobi.data.DataCache; import com.yami.trading.huobi.data.internal.DepthTimeObject; import com.yami.trading.huobi.data.internal.KlineService; import com.yami.trading.huobi.data.internal.TradeTimeObject; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.Month; import java.time.ZoneId; import java.time.ZonedDateTime; 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://onjdo.com/stock/api/live/getLiveRates"; private static Logger logger = LoggerFactory.getLogger(XinLangDataServiceImpl.class); @Autowired private KlineService klineService; @Autowired private ItemService itemService; public static void main(String[] args) { XinLangDataServiceImpl service = new XinLangDataServiceImpl(); // List sz300750 = service.buildOneYearPeriod("AAPL"); // System.out.println(sz300750.size()); List eurusd = service.getTimeseriesByPeriodOneDay("EURUSD"); System.out.println(JSONObject.toJSONString(eurusd)); } /** * 获取原始的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 realtimeSingle(String symbol) { List list = new ArrayList<>(); try { Map param = new HashMap<>(); param.put("currency", symbol); String result = HttpHelper.getJSONFromHttpNew(live, param, HttpMethodType.GET); JSONObject resultJson = JSON.parseObject(result); String code = resultJson.getString("code"); if ("ok".equals(code)) { JSONArray dataArray = resultJson.getJSONArray("data"); for (int i = 0; i < dataArray.size(); i++) { JSONObject realtimeJson = dataArray.getJSONObject(i); Realtime realtime = new Realtime(); // realtime.setUuid(ApplicationUtil.getCurrentTimeUUID()); String currency; currency = realtimeJson.getString("currency"); int decimal = itemService.getDecimal(currency); realtime.setSymbol(currency); realtime.setName(currency); Long timestamp = realtimeJson.getLong("timestamp"); if (timestamp.toString().length() > 13) { timestamp = timestamp / 1000; } realtime.setTs(timestamp); realtime.setOpen(realtimeJson.getBigDecimal("open").setScale(decimal, RoundingMode.HALF_UP).doubleValue()); realtime.setClose(realtimeJson.getBigDecimal("mid").setScale(decimal, RoundingMode.HALF_UP).doubleValue()); realtime.setHigh(realtimeJson.getBigDecimal("high").setScale(decimal, RoundingMode.HALF_UP).doubleValue()); realtime.setLow(realtimeJson.getBigDecimal("low").setScale(decimal, RoundingMode.HALF_UP).doubleValue()); realtime.setMarketCapital(realtimeJson.getLong("marketCapital")); realtime.setFloatMarketCapital(realtimeJson.getLong("floatMarketCapital")); realtime.setPeForecast(null == realtimeJson.getDouble("peForecast") ? 0 : realtimeJson.getDouble("peForecast").doubleValue()); realtime.setVolumeRatio(null == realtimeJson.getDouble("volumeRatio") ? 0 : realtimeJson.getDouble("volumeRatio").doubleValue()); realtime.setTurnoverRate(null == realtimeJson.getDouble("turnoverRate") ? 0 : realtimeJson.getDouble("volumeRatio").doubleValue()); BigDecimal amount = realtimeJson.getBigDecimal("amount"); if (amount == null) { amount = BigDecimal.ZERO; } realtime.setAmount(amount.setScale(decimal, RoundingMode.HALF_UP).doubleValue()); BigDecimal volume = realtimeJson.getBigDecimal("volume"); if (volume == null) { volume = BigDecimal.ZERO; } realtime.setVolume(volume.setScale(decimal, RoundingMode.HALF_UP).doubleValue()); list.add(realtime); } } else { logger.error(" realtime()error, resultJson [ " + resultJson.toJSONString() + " ]"); } } catch (Exception e) { logger.error("error", e); } return list; } /** * 1day 历史数据 : 周期 1年 * 1week,1mon 历史数据 : 周期 5年 * 请求 350次 */ public Map> getDailyWeekMonthHistory(String symbol) { Map> map = new HashMap<>(); List oneDayPeriod = buildOneDayPeriod(symbol); 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); } @Retryable( value = {RuntimeException.class}, // 需要重试的异常类型 maxAttempts = 5, // 最大重试次数 backoff = @Backoff(delay = 2000) // 退避策略:每次重试之间的延迟 ) 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(data.getDouble("o")); kline.setClose(data.getDouble("c")); kline.setHigh(data.getDouble("h")); kline.setLow(data.getDouble("l")); kline.setVolume(0); kline.setAmount(0); resList.add(kline); } return resList; } @Retryable( value = {RuntimeException.class}, // 需要重试的异常类型 maxAttempts = 5, // 最大重试次数 backoff = @Backoff(delay = 2000) // 退避策略:每次重试之间的延迟 ) 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(Double.parseDouble(ds.get(1))); kline.setClose(Double.parseDouble(ds.get(4))); kline.setHigh(Double.parseDouble(ds.get(3))); kline.setLow(Double.parseDouble(ds.get(2))); kline.setVolume(0); kline.setAmount(0); resList.add(kline); } return resList; } }