package com.yami.trading.huobi.hobi.internal;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.http.HttpUtil;
|
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.google.common.collect.Maps;
|
import com.yami.trading.bean.data.domain.Kline;
|
import com.yami.trading.bean.data.domain.Realtime;
|
import com.yami.trading.huobi.data.internal.KlineService;
|
import com.yami.trading.huobi.hobi.http.HttpHelper;
|
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.util.*;
|
|
/**
|
* 华尔街见闻 外汇,大众商品,指数 接口
|
* @哪吒出海
|
*/
|
@Component
|
public class WallstreetcnDataServiceImpl {
|
|
/**
|
* 新接口 华尔街见闻
|
*/
|
public final static String klineUrl = "https://api-ddc-wscn.awtmt.com/market/kline?prod_code=%s&tick_count=500&period_type=%s&adjust_price_type=forward&fields=tick_at,open_px,close_px,high_px,low_px,turnover_volume,turnover_value,average_px,px_change,px_change_rate,avg_px,ma2";
|
|
public final static String klineDay = "https://api-ddc-wscn.awtmt.com/market/kline?prod_code=%s&tick_count=500&period_type=86400&adjust_price_type=forward&fields=tick_at,open_px,close_px,high_px,low_px,turnover_volume,turnover_value,average_px,px_change,px_change_rate,avg_px,ma2";
|
|
private static Logger logger = LoggerFactory.getLogger(XinLangDataServiceImpl.class);
|
|
@Autowired
|
private KlineService klineService;
|
@Autowired
|
private ItemService itemService;
|
|
|
/**
|
* 获取原始的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> realtimeSingle(String symbol) {
|
//logger.info("正在采集外汇行情数据: {}" ,symbol);
|
List<Realtime> list = new ArrayList<Realtime>();
|
try {
|
List<String> symbols = Splitter.on(",").trimResults().splitToList(symbol);
|
symbols.forEach(val -> {
|
Map<String, Object> realData = getRealData(val);
|
if (Objects.isNull(realData)) {
|
return;
|
}
|
Realtime realtime = new Realtime();
|
realtime.setSymbol(MapUtil.getStr(realData, "symbol"));
|
realtime.setName(MapUtil.getStr(realData, "prod_name"));
|
realtime.setOpen(Double.valueOf(MapUtil.getDouble(realData, "open_px")));
|
realtime.setClose(Double.valueOf(MapUtil.getDouble(realData, "last_px")));
|
realtime.setHigh(Double.valueOf(MapUtil.getDouble(realData, "high_px")));
|
realtime.setLow(Double.valueOf(MapUtil.getDouble(realData, "low_px")));
|
|
String pxChangeRate = MapUtil.getStr(realData, "px_change_rate");
|
String pxChange = MapUtil.getStr(realData, "px_change");
|
|
BigDecimal pxChangeRateBig = new BigDecimal(pxChangeRate).setScale(2, BigDecimal.ROUND_UP);
|
BigDecimal pxChangeBig = new BigDecimal(pxChange).setScale(6, BigDecimal.ROUND_UP);
|
|
realtime.setChangeRatio(pxChangeRateBig.doubleValue());
|
realtime.setNetChange(pxChangeBig.doubleValue());
|
realtime.setTs(MapUtil.getLong(realData, "update_time"));
|
realtime.setAmount(new BigDecimal("0").doubleValue());
|
realtime.setVolume(new BigDecimal("0").doubleValue());
|
list.add(realtime);
|
});
|
} catch (Exception e) {
|
logger.error("error", e);
|
}
|
return list;
|
}
|
|
|
public Map<String, Object> getRealData(String symbol) {
|
//Item bySymbol = itemService.findBySymbol(symbol);
|
//if(Item.commodities.equalsIgnoreCase(bySymbol.getCategory())){
|
// symbol = symbol + ".OTC";
|
//}
|
symbol = symbol + ".OTC";
|
String url = "https://api-ddc-wscn.awtmt.com/market/real?fields=symbol,en_name,prod_name,last_px,px_change,px_change_rate,high_px,low_px,open_px,preclose_px,market_value,turnover_volume,turnover_ratio,turnover_value,dyn_pb_rate,amplitude,dyn_pe,trade_status,circulation_value,update_time,price_precision,week_52_high,week_52_low,static_pe,source&prod_code=" + symbol.toUpperCase();
|
String body = HttpUtil.get(url);
|
JSONObject jsonObj = JSON.parseObject(body);
|
JSONObject dataObj = jsonObj.getJSONObject("data");
|
JSONArray fieldsArr = dataObj.getJSONArray("fields");
|
JSONObject snapshotObj = dataObj.getJSONObject("snapshot");
|
JSONArray snapshotArr = snapshotObj.getJSONArray(symbol.toUpperCase());
|
if (CollUtil.isEmpty(snapshotArr)) {
|
return null;
|
}
|
// 创建Map存放结果
|
Map<String, Object> snapshotMap = new HashMap<>();
|
|
// 将fields和snapshot数据对应起来放入Map
|
for (int i = 0; i < fieldsArr.size(); i++) {
|
String key = fieldsArr.getString(i);
|
Object value = snapshotArr.get(i);
|
snapshotMap.put(key, value);
|
}
|
return snapshotMap;
|
}
|
|
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 4小时
|
* 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 1小时
|
* 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<Map<String, Object>> getKlineData(String urlStr, String symbol, String scale) {
|
symbol = symbol + ".OTC";
|
String url = String.format(urlStr, symbol, scale);
|
String body = HttpUtil.get(url);
|
JSONObject jsonObj = JSON.parseObject(body);
|
JSONObject dataObj = jsonObj.getJSONObject("data");
|
JSONArray fieldsArr = dataObj.getJSONArray("fields");
|
JSONObject candleObj = dataObj.getJSONObject("candle");
|
JSONObject candleArr = candleObj.getJSONObject(symbol.toUpperCase());
|
JSONArray klineArr = candleArr.getJSONArray("lines");
|
if (CollUtil.isEmpty(klineArr)) {
|
return null;
|
}
|
// 创建Map存放结果
|
List<Map<String, Object>> snapshotMap = Lists.newArrayList();
|
|
for (int i = 0; i < klineArr.size(); i++) {
|
Map<String, Object> dataMap = Maps.newHashMap();
|
JSONArray dataArr = klineArr.getJSONArray(i);
|
for (int i1 = 0; i1 < dataArr.size(); i1++) {
|
String key = fieldsArr.getString(i1);
|
Object value = dataArr.get(i1);
|
dataMap.put(key, value);
|
}
|
snapshotMap.add(dataMap);
|
}
|
return snapshotMap;
|
}
|
|
@Retryable(
|
value = {RuntimeException.class}, // 需要重试的异常类型
|
maxAttempts = 5, // 最大重试次数
|
backoff = @Backoff(delay = 2000) // 退避策略:每次重试之间的延迟
|
)
|
public List<Kline> getTimeseriesByPeriodMinute(String currency, int scale, String period) {
|
|
List<Kline> resList = Lists.newArrayList();
|
List<Map<String, Object>> klineData = getKlineData(klineUrl, currency, String.valueOf(scale));
|
|
for (Map<String, Object> result : klineData) {
|
Kline kline = new Kline();
|
kline.setSymbol(currency);
|
kline.setPeriod(period);
|
// 转换成时间戳(毫秒)
|
long ts = MapUtil.getLong(result, "tick_at") * 1000;
|
kline.setTs(ts);
|
kline.setOpen(Double.valueOf(MapUtil.getStr(result, "open_px")));
|
kline.setClose(Double.valueOf(MapUtil.getStr(result, "close_px")));
|
kline.setHigh(Double.valueOf(MapUtil.getStr(result, "high_px")));
|
kline.setLow(Double.valueOf(MapUtil.getStr(result, "low_px")));
|
kline.setVolume(Double.valueOf("0"));
|
kline.setAmount(Double.valueOf("0"));
|
resList.add(kline);
|
}
|
return resList;
|
}
|
|
|
@Retryable(
|
value = {RuntimeException.class}, // 需要重试的异常类型
|
maxAttempts = 5, // 最大重试次数
|
backoff = @Backoff(delay = 2000) // 退避策略:每次重试之间的延迟
|
)
|
public List<Kline> getTimeseriesByPeriodOneDay(String currency) {
|
List<Kline> resList = Lists.newArrayList();
|
List<Map<String, Object>> klineData = getKlineData(klineDay, currency, "");
|
for (int i = 0; i < klineData.size(); i++) {
|
Map<String, Object> kData = klineData.get(i);
|
Kline kline = new Kline();
|
kline.setSymbol(currency);
|
kline.setPeriod(Kline.PERIOD_1DAY);
|
long ts = MapUtil.getLong(kData,"tick_at") * 1000;
|
kline.setTs(ts);
|
kline.setOpen(Double.valueOf(MapUtil.getStr(kData, "open_px")));
|
kline.setClose(Double.valueOf(MapUtil.getStr(kData, "close_px")));
|
kline.setHigh(Double.valueOf(MapUtil.getStr(kData, "high_px")));
|
kline.setLow(Double.valueOf(MapUtil.getStr(kData, "low_px")));
|
kline.setVolume(Double.valueOf(0));
|
kline.setAmount(Double.valueOf(0));
|
resList.add(kline);
|
}
|
return resList;
|
}
|
|
|
|
}
|