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<Realtime> usdsgd = service.realtimeSingle("USDJPY");
|
for (Realtime re : usdsgd) {
|
System.out.println(JSONObject.toJSONString(re));
|
}
|
// List<Kline> sz300750 = service.buildOneYearPeriod("AAPL");
|
// System.out.println(sz300750.size());
|
// List<Kline> eurusd = service.getTimeseriesByPeriodOneDay("EURUSD");
|
// System.out.println(JSONObject.toJSONString(eurusd));
|
}
|
public Map<String, Object> createRequest(List<String> strings) {
|
Map<String, Object> requestData = new HashMap<>();
|
Map<String, Object> data = new HashMap<>();
|
List<Map<String, Object>> dataList = new ArrayList<>();
|
for (String symbolCode : strings) {
|
for (int i = 1; i <= 3; i++) {
|
Map<String, Object> 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<String, Object> createRequestTick(List<String> 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<String, Object> 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<Realtime> realtimeNewPrice(String symbols,List<Realtime> realtimes) {
|
//获取最新价
|
try{
|
List<String> strings = Arrays.asList(symbols.split(","));
|
Map<String, Object> 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<AlltickNewPriceResult> 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<String, Object> 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<AlltickBatchKlineResult> 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<Realtime> realtimeSingle(String symbols) {
|
List<Realtime> list = new ArrayList<Realtime>();
|
try {
|
List<String> strings = Arrays.asList(symbols.split(","));
|
Map<String, Object> 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<AlltickNewPriceResult> 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> realtime(String symbols) {
|
List<Realtime> realtimeList = realtimeSingle(symbols);
|
return realtimeList;
|
}
|
|
/**
|
* 1day 历史数据 : 周期 1年
|
* 1week,1mon 历史数据 : 周期 5年
|
* 请求 350次
|
*/
|
public Map<String, List<Kline>> getDailyWeekMonthHistory(String symbol) {
|
Map<String, List<Kline>> map = new HashMap<>();
|
List<Kline> oneDayPeriod = buildOneDayPeriod(symbol);
|
|
// public List<Kline> calculateKline(String symbol, int seq, String period, List<Kline> 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<Kline> buildOneDayPeriod(String currency) {
|
return getTimeseriesByPeriodOneDay(currency);
|
|
}
|
|
|
|
|
|
/**
|
* 雪球支持120分钟的,讲120分钟的,
|
* Hourly
|
* 4hourly 3月
|
*/
|
public List<Kline> getTimeseriesForFourHourly(String currency) {
|
return getTimeseriesByPeriodMinute(currency, 240, Kline.PERIOD_4HOUR);
|
}
|
|
/**
|
* Hourly
|
* 1hourly 2个小时
|
*/
|
public List<Kline> getTimeseriesForTwoHourly(String currency) {
|
return getTimeseriesByPeriodMinute(currency, 120, Kline.PERIOD_2HOUR);
|
}
|
|
/**
|
* Hourly
|
* 1hourly 1月
|
*/
|
public List<Kline> getTimeseriesForOneHourly(String currency) {
|
return getTimeseriesByPeriodMinute(currency, 60, Kline.PERIOD_60MIN);
|
}
|
|
/**
|
* Minute
|
* 30minute 10天
|
* 15minute 5天
|
* 5minute 2天
|
* 1minute 1天
|
*/
|
public List<Kline> getTimeseriesOneMinute(String currency) {
|
return getTimeseriesByPeriodMinute(currency, 1, Kline.PERIOD_1MIN);
|
|
}
|
|
/**
|
* Minute
|
* 30minute 10天
|
* 15minute 5天
|
* 5minute 2天
|
* 1minute 1天
|
*/
|
public List<Kline> getTimeseriesFiveMinute(String currency) {
|
return getTimeseriesByPeriodMinute(currency, 5, Kline.PERIOD_5MIN);
|
|
}
|
|
/**
|
* Minute
|
* 30minute 10天
|
* 15minute 5天
|
* 5minute 2天
|
* 1minute 1天
|
*/
|
public List<Kline> getTimeseriesFifteenMinute(String currency) {
|
return getTimeseriesByPeriodMinute(currency, 15, Kline.PERIOD_15MIN);
|
|
}
|
|
/**
|
* Minute
|
* 30minute 15
|
* 15minute 15
|
* 5minute 15
|
* 1minute 15
|
*/
|
public List<Kline> getTimeseriesThirtyMinute(String currency) {
|
return getTimeseriesByPeriodMinute(currency, 30, Kline.PERIOD_30MIN);
|
}
|
|
public List<Kline> 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<Kline> 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<Kline> 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<Kline> 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<String> 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;
|
|
}
|
|
|
|
}
|