first commit

This commit is contained in:
Ray
2026-02-19 03:37:37 +08:00
commit ccfd8c79a4
2813 changed files with 453657 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path:

View File

@@ -0,0 +1,172 @@
<%@ page language="java" pageEncoding="utf-8"%>
<%@ include file="include/pagetop.jsp"%>
<!DOCTYPE html>
<html>
<head>
<%@ include file="include/head.jsp"%>
</head>
<body>
<%@ include file="include/loading.jsp"%>
<%@ include file="include/top.jsp"%>
<%@ include file="include/menu_left.jsp"%>
<!-- //////////////////////////////////////////////////////////////////////////// -->
<!-- START CONTENT -->
<div class="content">
<!-- //////////////////////////////////////////////////////////////////////////// -->
<!-- START CONTAINER -->
<div class="container-default">
<h3>可交易品种库</h3>
<%@ include file="include/alert.jsp"%>
<!-- START queryForm -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-title">查询条件</div>
<div class="panel-body">
<form class="form-horizontal"
action="<%=basePath%>normal/adminSymbolsAction!list.action"
method="post" id="queryForm">
<input type="hidden" name="pageNo" id="pageNo"
value="${param.pageNo}">
<div class="col-md-12 col-lg-8">
<fieldset>
<div class="control-group">
<div class="controls">
<s:textfield id="quote_currency" name="quote_currency" cssClass="form-control " placeholder="报价币种"/>
</div>
</div>
</fieldset>
</div>
<div class="col-md-12 col-lg-2">
<button type="submit" class="btn btn-light btn-block">查询</button>
</div>
</form>
<sec:authorize ifAnyGranted="ROLE_ROOT,ROLE_ADMIN">
<div class="col-md-12 col-lg-4" style="margin-top: 10px;">
<div class="mailbox clearfix">
<div class="mailbox-menu">
<ul class="menu">
<li>
<button type="button" onclick="reload()" class="btn btn-default ">同步远程数据库</button></li>
</ul>
</div>
</div>
</div>
</sec:authorize>
</div>
</div>
</div>
</div>
<!-- END queryForm -->
<div class="row">
<div class="col-md-12">
<!-- Start Panel -->
<div class="panel panel-default">
<div class="panel-title">查询结果</div>
<div class="panel-body">
<table class="table table-bordered table-striped">
<thead>
<tr>
<td>交易对</td>
<td>基础币种</td>
<td>报价币种</td>
<td>报价精度(小数位)</td>
<td>交易对杠杆最大倍数</td>
<td>状态</td>
<td></td>
</tr>
</thead>
<tbody>
<s:iterator value="page.elements" status="stat">
<tr>
<td><s:property value="symbol" /></td>
<td><s:property value="base_currency" /></td>
<td><s:property value="quote_currency" /></td>
<td><s:property value="price_precision" /></td>
<td><s:property value="leverage_ratio" /></td>
<td><s:property value="state" /></td>
<td>
<sec:authorize ifAnyGranted="ROLE_ROOT,ROLE_ADMIN">
<div class="btn-group">
<button type="button" class="btn btn-light">操作</button>
<button type="button" class="btn btn-light dropdown-toggle"
data-toggle="dropdown" aria-expanded="false">
<span class="caret"></span> <span class="sr-only">Toggle
Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a
href="<%=basePath%>normal/adminItemAction!toAdd.action?symbol_data=<s:property value="symbol" />&symbol=<s:property value="base_currency" />">添加到交易品种</a></li>
</ul>
</div>
</sec:authorize>
</td>
</tr>
</s:iterator>
</tbody>
</table>
<%@ include file="include/page_simple.jsp"%>
<nav>
</div>
</div>
<!-- End Panel -->
</div>
</div>
</div>
<!-- END CONTAINER -->
<!-- //////////////////////////////////////////////////////////////////////////// -->
<%@ include file="include/footer.jsp"%>
</div>
<!-- End Content -->
<!-- //////////////////////////////////////////////////////////////////////////// -->
<%@ include file="include/js.jsp"%>
</body>
<sec:authorize ifAnyGranted="ROLE_ADMIN,ROLE_ROOT">
<form action="<%=basePath%>normal/adminSymbolsAction!reload.action" method="post"
id="reload">
</form>
<script type="text/javascript">
function reload() {
swal({
title : "是否同步远程数据库?",
text : "",
type : "warning",
showCancelButton : true,
confirmButtonColor : "#DD6B55",
confirmButtonText : "确认",
closeOnConfirm : false
}, function() {
document.getElementById("reload").submit();
});
}
</script>
</sec:authorize>
</html>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="project.data.Realtime" table="T_REALTIME">
<id name="id" type="java.lang.String">
<column name="UUID" />
<generator class="uuid.hex" />
</id>
<property name="symbol" type="java.lang.String">
<column name="SYMBOL" />
</property>
<property name="ts" type="int">
<column name="TS" />
</property>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="open" type="double">
<column name="OPEN" />
</property>
<property name="high" type="double">
<column name="HIGH" />
</property>
<property name="low" type="double">
<column name="LOW" />
</property>
<property name="close" type="double">
<column name="CLOSE" />
</property>
<property name="volume" type="double">
<column name="VOLUME" />
</property>
<property name="amount" type="double">
<column name="AMOUNT" />
</property>
</class>
</hibernate-mapping>

View File

@@ -0,0 +1,11 @@
admin
<!-- hobi -->
<value>adminSymbolsService</value>
<value>adminContractSymbolsService</value>
data
<!-- hobi -->
<value>dataDBService</value>
<value>klineService</value>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<bean id="dataService"
class="project.data.internal.DataServiceImpl">
<property name="remoteDataService" ref="remoteDataService" />
</bean>
<dubbo:reference id="remoteDataService"
interface="project.data.DataService" check="false" />
</beans>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:reference id="hobiDataService"
interface="project.hobi.HobiDataService" check="false" />
<bean id="adminSymbolsService"
class="project.hobi.internal.AdminSymbolsServiceImpl">
<property name="hibernateTemplate" ref="hibernateTemplate" />
<property name="pagedQueryDao" ref="pagedDao" />
<property name="hobiDataService" ref="hobiDataService" />
</bean>
<bean id="adminContractSymbolsService"
class="project.hobi.internal.AdminContractSymbolsServiceImpl">
<property name="hibernateTemplate" ref="hibernateTemplate" />
<property name="pagedQueryDao" ref="pagedDao" />
<property name="hobiDataService" ref="hobiDataService" />
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<dubbo:reference id="klineInitService"
interface="project.data.internal.KlineInitService" check="false" />
</beans>

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<bean id="klineInitService"
class="project.data.internal.KlineInitServiceImpl">
<property name="klineService" ref="klineService" />
</bean>
<dubbo:service
interface="project.data.internal.KlineInitService"
ref="klineInitService" />
<bean id="hobiDataService"
class="project.hobi.internal.HobiDataServiceImpl">
<property name="itemService" ref="itemService" />
</bean>
<dubbo:service interface="project.hobi.HobiDataService"
ref="hobiDataService" />
<bean id="cleanDataJob" class="project.data.job.CleanDataJob">
<property name="itemService" ref="itemService" />
<property name="dataDBService" ref="dataDBService" />
<property name="klineService" ref="klineService" />
</bean>
<bean id="dataDBService"
class="project.data.internal.DataDBServiceImpl">
<property name="hibernateTemplate" ref="hibernateTemplate" />
<property name="namedParameterJdbcTemplate"
ref="namedParameterJdbcTemplate" />
<property name="sysparaService" ref="sysparaService" />
<property name="pagedQueryDao" ref="pagedDao" />
<property name="itemService" ref="itemService" />
</bean>
<bean id="klineService"
class="project.data.internal.KlineServiceImpl">
<property name="itemService" ref="itemService" />
<property name="hobiDataService" ref="hobiDataService" />
<property name="hibernateTemplate" ref="hibernateTemplate" />
<property name="sysparaService" ref="sysparaService" />
<property name="pagedQueryDao" ref="pagedDao" />
<property name="namedParameterJdbcTemplate"
ref="namedParameterJdbcTemplate" />
</bean>
<bean id="klineCacheJob" class="project.data.job.KlineCacheJob">
<property name="itemService" ref="itemService" />
<property name="hobiDataService" ref="hobiDataService" />
</bean>
<bean id="dataServer" class="project.data.job.DataServer">
<property name="hobiDataService" ref="hobiDataService" />
<property name="taskExecutor" ref="dataServerThreadPool" />
</bean>
<bean id="dataServerThreadPool"
class="kernel.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="1" />
<property name="keepAliveSeconds" value="60" />
<property name="maxPoolSize" value="2" />
<property name="queueCapacity" value="50" />
<property name="rejectedExecutionHandler"
ref="dataServerThreadRejectExecutingHandler" />
</bean>
<bean id="dataServerThreadRejectExecutingHandler"
class="kernel.util.RejectExecutionHandlerDelegator">
<property name="rejectExecutionHandlers">
<list>
<bean
class="project.data.job.OffLineEventRejectExecutingHandler" />
</list>
</property>
</bean>
<bean id="saveRealtimeServer"
class="project.data.job.SaveRealtimeServer">
<property name="dataDBService" ref="dataDBService" />
</bean>
<bean id="dataFrequencyServer"
class="project.data.job.DataFrequencyServer">
<property name="itemService" ref="itemService" />
<property name="hobiDataService" ref="hobiDataService" />
</bean>
<bean id="adjustmentValueService"
class="project.data.internal.AdjustmentValueServiceImpl">
<property name="hibernateTemplate" ref="hibernateTemplate" />
<property name="dataService" ref="dataService" />
<property name="itemService" ref="itemService" />
</bean>
<dubbo:service
interface="project.data.AdjustmentValueService"
ref="adjustmentValueService" />
<bean id="dataService"
class="project.data.internal.RemoteDataServiceImpl">
<property name="hibernateTemplate" ref="hibernateTemplate" />
<property name="itemService" ref="itemService" />
<property name="sysparaService" ref="sysparaService" />
<property name="klineService" ref="klineService" />
</bean>
<dubbo:service interface="project.data.DataService"
ref="dataService" />
</beans>

23
comm/Hobi/config/struts2.xml Executable file
View File

@@ -0,0 +1,23 @@
admin
<action name="adminSymbolsAction"
class="project.hobi.web.AdminSymbolsAction">
<result name="list">/symbols_list.jsp</result>
</action>
<action name="adminContractSymbolsAction"
class="project.hobi.web.AdminContractSymbolsAction">
<result name="list">/contract_manage_add_symbols_list.jsp</result>
</action>
api
<action name="realtime" class="project.api.RealtimeAction">
</action>
<action name="trend" class="project.api.TrendAction">
</action>
<action name="depth" class="project.api.DepthAction">
</action>
<action name="trade" class="project.api.TradeAction">
</action>
<action name="kline" class="project.api.KlineAction">
</action>

View File

@@ -0,0 +1,48 @@
DROP TABLE IF EXISTS `T_REALTIME`;
CREATE TABLE `T_REALTIME` (
`UUID` varchar(32) NOT NULL COMMENT '<27><><EFBFBD><EFBFBD>',
`SYMBOL` varchar(32) COMMENT '<27><><EFBFBD><EFBFBD>',
`TS` bigint ,
`NAME` varchar(64) ,
`OPEN` double ,
`HIGH` double ,
`LOW` double ,
`CLOSE` double ,
`AMOUNT` double ,
`VOLUME` double ,
PRIMARY KEY (`UUID`),
KEY `INDEX_REALTIME_TS` (`TS`),
KEY `INDEX_REALTIME_SYMBOL` (`SYMBOL`,`TS`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `T_KLINE`;
CREATE TABLE `T_KLINE` (
`UUID` varchar(32) NOT NULL COMMENT '<27><><EFBFBD><EFBFBD>',
`SYMBOL` varchar(32) COMMENT '<27><><EFBFBD><EFBFBD>',
`TS` bigint ,
`OPEN` double ,
`HIGH` double ,
`LOW` double ,
`CLOSE` double ,
`AMOUNT` double ,
`VOLUME` double ,
`PERIOD` varchar(64) ,
PRIMARY KEY (`UUID`),
KEY `INDEX_KLINE_TS` (`TS`),
KEY `INDEX_KLINE_SYMBOL` (`SYMBOL`,`TS`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `T_SYMBOLS`;
CREATE TABLE `T_SYMBOLS` (
`UUID` varchar(32) NOT NULL ,
`SYMBOL` varchar(32) ,
`BASE_CURRENCY` varchar(32) ,
`QUOTE_CURRENCY` varchar(32) ,
`PRICE_PRECISION` int(11) ,
`STATE` varchar(32) ,
`LEVERAGE_RATIO` double ,
PRIMARY KEY (`UUID`),
KEY `INDEX_SYMBOLS_SYMBOL` (`SYMBOL`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@@ -0,0 +1,24 @@
package project.data;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class AdjustmentValueCache {
/**
* 当前值
*/
private static volatile Map<String, Double> currentValue = new ConcurrentHashMap();
/**
* 延时值
*/
private static volatile Map<String, AdjustmentValue> delayValue = new ConcurrentHashMap();
public static Map<String, Double> getCurrentValue() {
return currentValue;
}
public static Map<String, AdjustmentValue> getDelayValue() {
return delayValue;
}
}

View File

@@ -0,0 +1,121 @@
package project.data;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import kernel.util.StringUtils;
import project.data.internal.DepthTimeObject;
import project.data.internal.KlineTimeObject;
import project.data.internal.TradeTimeObject;
import project.data.internal.TrendTimeObject;
import project.data.model.Kline;
import project.data.model.Realtime;
public class DataCache {
/**
* 分时
*/
private volatile static Map<String, TrendTimeObject> trend = new ConcurrentHashMap<String, TrendTimeObject>();
/**
* K线
*/
private volatile static Map<String, KlineTimeObject> kline = new ConcurrentHashMap<String, KlineTimeObject>();
/**
* 实时数据
*/
private volatile static Map<String, Realtime> realtime = new ConcurrentHashMap<String, Realtime>();
/**
* 实时历史数据
*/
private volatile static Map<String, List<Realtime>> realtimeHistory = new ConcurrentHashMap<String, List<Realtime>>();
/**
* 最高最低
*/
private volatile static Map<String, Double> realtimeHigh = new ConcurrentHashMap<String, Double>();
private volatile static Map<String, Double> realtimeLow = new ConcurrentHashMap<String, Double>();
/**
* 向前24小时时间点的开盘价
*/
private volatile static Map<String, Double> realtime24HBeforeOpen = new ConcurrentHashMap<String, Double>();
/**
* 市场深度数据
*/
private volatile static Map<String, DepthTimeObject> depth = new ConcurrentHashMap<String, DepthTimeObject>();
/**
* 近期交易记录
*/
private volatile static Map<String, TradeTimeObject> trade = new ConcurrentHashMap<String, TradeTimeObject>();
private volatile static Map<String, Kline> kline_hobi = new ConcurrentHashMap<String, Kline>();
public static TrendTimeObject getTrend(String symbol) {
return trend.get(symbol);
}
public static void putTrend(String symbol, TrendTimeObject model) {
trend.put(symbol, model);
}
public static KlineTimeObject getKline(String symbol, String line) {
String key = symbol;
if (!StringUtils.isNullOrEmpty(line)) {
key = key + "_" + line;
}
return kline.get(key);
}
public static void putKline(String symbol, String line, KlineTimeObject model) {
String key = symbol;
if (!StringUtils.isNullOrEmpty(line)) {
key = key + "_" + line;
}
kline.put(key, model);
}
public static Realtime getRealtime(String symbol) {
return realtime.get(symbol);
}
public static void putRealtime(String symbol, Realtime model) {
realtime.put(symbol, model);
}
public static Map<String, List<Realtime>> getRealtimeHistory() {
return realtimeHistory;
}
public static void setRealtimeHistory(Map<String, List<Realtime>> realtimeHistory) {
DataCache.realtimeHistory = realtimeHistory;
}
public static Map<String, Double> getRealtimeHigh() {
return realtimeHigh;
}
public static Map<String, Double> getRealtimeLow() {
return realtimeLow;
}
public static Map<String, DepthTimeObject> getDepth() {
return depth;
}
public static Map<String, TradeTimeObject> getTrade() {
return trade;
}
public static Map<String, Kline> getKline_hobi() {
return kline_hobi;
}
public static Map<String, Double> getRealtime24HBeforeOpen() {
return realtime24HBeforeOpen;
}
}

View File

@@ -0,0 +1,32 @@
package project.data;
import java.util.List;
import project.data.model.Realtime;
public interface DataDBService {
/**
* 异步保存
*/
public void saveAsyn(Realtime entity);
/**
* 数据库最新的实时价格
*/
public Realtime get(String symbol);
/**
* 批量保存
*/
public void saveBatch(List<Realtime> entities);
public List<Realtime> findRealtimeOneDay(String symbol);
/**
* 删除数据库里Realtime
*/
public void deleteRealtime(int days);
public void updateOptimize(String table);
}

View File

@@ -0,0 +1,80 @@
package project.data.internal;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import kernel.exception.BusinessException;
import kernel.util.Arith;
import project.data.AdjustmentValue;
import project.data.AdjustmentValueCache;
import project.data.AdjustmentValueService;
import project.data.DataService;
import project.data.model.Realtime;
import project.item.ItemService;
import project.item.model.Item;
public class AdjustmentValueServiceImpl extends HibernateDaoSupport implements AdjustmentValueService {
private DataService dataService;
private ItemService itemService;
public void adjust(String symbol, double value, double second) {
if (value == 0.0D) {
return;
}
Realtime realtime = dataService.realtime(symbol).get(0);
double new_price = realtime.getClose();
double plus = Math.abs(value);
if (Arith.div(plus, new_price) > 0.1D) {
throw new BusinessException("调整偏差过大超过10%");
}
if (second <= 0) {
/**
* 即时生效
*/
Double currentValue = AdjustmentValueCache.getCurrentValue().get(symbol);
if (currentValue == null) {
AdjustmentValueCache.getCurrentValue().put(symbol, value);
} else {
AdjustmentValueCache.getCurrentValue().put(symbol, Arith.add(currentValue, value));
}
/*
* 持久化缓存
*/
Item item = this.itemService.cacheBySymbol(symbol, false);
if (item.getAdjustment_value() != AdjustmentValueCache.getCurrentValue().get(symbol)) {
item.setAdjustment_value(AdjustmentValueCache.getCurrentValue().get(symbol));
itemService.update(item);
}
} else {
AdjustmentValue adjustmentValue = new AdjustmentValue();
adjustmentValue.setSymbol(symbol);
adjustmentValue.setValue(value);
adjustmentValue.setSecond(second);
AdjustmentValueCache.getDelayValue().put(symbol, adjustmentValue);
}
}
@Override
public Double getCurrentValue(String symbol) {
return AdjustmentValueCache.getCurrentValue().get(symbol);
}
@Override
public AdjustmentValue getDelayValue(String symbol) {
return AdjustmentValueCache.getDelayValue().get(symbol);
}
public void setDataService(DataService dataService) {
this.dataService = dataService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,156 @@
package project.data.internal;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import kernel.util.Arith;
import kernel.util.DateUtils;
import kernel.web.PagedQueryDao;
import project.data.DataCache;
import project.data.DataDBService;
import project.data.job.RealtimeQueue;
import project.data.model.Realtime;
import project.item.ItemService;
import project.item.model.Item;
import project.syspara.SysparaService;
public class DataDBServiceImpl extends HibernateDaoSupport implements DataDBService {
private NamedParameterJdbcOperations namedParameterJdbcTemplate;
private SysparaService sysparaService;
private PagedQueryDao pagedQueryDao;
private ItemService itemService;
@Override
public void saveAsyn(Realtime entity) {
Realtime current = DataCache.getRealtime(entity.getSymbol());
if (current == null || current.getTs() != entity.getTs()) {
Item item = itemService.cacheBySymbol(entity.getSymbol(), true);
/**
* 交易量倍数不为空或0时修改倍数
*/
if (item.getMultiple() > 0) {
entity.setVolume(Arith.mul(entity.getVolume(), item.getMultiple()));
entity.setAmount(Arith.mul(entity.getAmount(), item.getMultiple()));
}
Double high = DataCache.getRealtimeHigh().get(entity.getSymbol());
if (high != null && high >= entity.getClose()) {
entity.setHigh(high);
}
Double low = DataCache.getRealtimeLow().get(entity.getSymbol());
if (low != null && low <= entity.getClose()) {
entity.setLow(low);
}
Double h24Before = DataCache.getRealtime24HBeforeOpen().get(entity.getSymbol());
if (h24Before != null) {
entity.setOpen(h24Before);
}
/**
* 时间有变化,才保存
*/
DataCache.putRealtime(entity.getSymbol(), entity);
List<Realtime> list = DataCache.getRealtimeHistory().get(entity.getSymbol());
if (list == null) {
list = new LinkedList<Realtime>();
}
if (entity.getLow() > 0) {
/**
* 修正最低为0的BUG直接丢弃
*/
list.add(entity);
DataCache.getRealtimeHistory().put(entity.getSymbol(), list);
RealtimeQueue.add(entity);
}
}
}
@Override
public void saveBatch(List<Realtime> entities) {
for (int i = 0; i < entities.size(); i++) {
this.getHibernateTemplate().saveOrUpdate(entities.get(i));
}
}
@Override
public Realtime get(String symbol) {
StringBuffer queryString = new StringBuffer(" FROM Realtime where 1=1 ");
Map<String, Object> parameters = new HashMap();
queryString.append(" and symbol = :symbol ");
parameters.put("symbol", symbol);
List<Realtime> list = this.pagedQueryDao.pagedQueryHql(0, 1, queryString.toString(), parameters).getElements();
if (list.size() > 0) {
return list.get(0);
}
return null;
}
public void deleteRealtime(int days) {
Map<String, Object> parameters = new HashMap();
Long ts = DateUtils.addDate(new Date(), days).getTime();
parameters.put("ts", ts);
this.namedParameterJdbcTemplate.update("DELETE FROM T_REALTIME WHERE ts < :ts", parameters);
}
@Override
public void updateOptimize(String table) {
Map<String, Object> parameters = new HashMap();
this.namedParameterJdbcTemplate.update("optimize table " + table, parameters);
}
@Override
public List<Realtime> findRealtimeOneDay(String symbol) {
int interval = this.sysparaService.find("data_interval").getInteger().intValue() / 1000;
int num = (24 * 60 * 60) / interval;
StringBuffer queryString = new StringBuffer(" FROM Realtime WHERE 1=1 ");
Map<String, Object> parameters = new HashMap();
queryString.append(" and symbol = :symbol ");
parameters.put("symbol", symbol);
queryString.append(" order by ts asc");
List<Realtime> list = this.pagedQueryDao.pagedQueryHql(0, num, queryString.toString(), parameters)
.getElements();
return list;
}
public void setNamedParameterJdbcTemplate(NamedParameterJdbcOperations namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
public void setSysparaService(SysparaService sysparaService) {
this.sysparaService = sysparaService;
}
public void setPagedQueryDao(PagedQueryDao pagedQueryDao) {
this.pagedQueryDao = pagedQueryDao;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,175 @@
package project.data.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import kernel.util.DateUtils;
import project.data.DataService;
import project.data.model.Depth;
import project.data.model.Kline;
import project.data.model.Realtime;
import project.data.model.Trade;
import project.data.model.Trend;
import project.syspara.SysparaService;
public class DataServiceImpl extends HibernateDaoSupport implements DataService {
private volatile static Map<String, TimeObject> cache = new ConcurrentHashMap<String, TimeObject>();
private DataService remoteDataService;
private SysparaService sysparaService;
/**
* 行情实时价格
*/
@Override
public List<Realtime> realtime(String symbol) {
String key = "realtime_" + symbol;
List<Realtime> list = new ArrayList<Realtime>();
TimeObject timeObject = cache.get(key);
if (isRemote(timeObject)) {
list = remoteDataService.realtime(symbol);
RealtimeTimeObject realtimeTimeObject = new RealtimeTimeObject();
realtimeTimeObject.setLastTime(new Date());
realtimeTimeObject.setList(list);
cache.put(key, realtimeTimeObject);
} else {
list = ((RealtimeTimeObject) timeObject).getList();
}
return list;
}
/**
* 分时图
*/
@Override
public List<Trend> trend(String symbol) {
String key = "trend_" + symbol;
List<Trend> list = new ArrayList<Trend>();
TimeObject timeObject = cache.get(key);
if (isRemote(timeObject)) {
list = remoteDataService.trend(symbol);
TrendTimeObject trendTimeObject = new TrendTimeObject();
trendTimeObject.setLastTime(new Date());
trendTimeObject.setTrend(list);
cache.put(key, trendTimeObject);
} else {
list = ((TrendTimeObject) timeObject).getTrend();
}
return list;
}
/**
* Kline
*/
@Override
public List<Kline> kline(String symbol, String line) {
String key = "kline_" + symbol + "_" + line;
List<Kline> list = new ArrayList<Kline>();
TimeObject timeObject = cache.get(key);
if (isRemote(timeObject)) {
list = remoteDataService.kline(symbol, line);
Collections.sort(list); // 按时间升序
KlineTimeObject klineTimeObject = new KlineTimeObject();
klineTimeObject.setLastTime(new Date());
klineTimeObject.setKline(list);
cache.put(key, klineTimeObject);
} else {
list = ((KlineTimeObject) timeObject).getKline();
}
return list;
}
/**
* 深度数据
*/
@Override
public Depth depth(String symbol) {
String key = "depth_" + symbol;
Depth depth = new Depth();
TimeObject timeObject = cache.get(key);
if (isRemote(timeObject)) {
depth = remoteDataService.depth(symbol);
DepthTimeObject depthTimeObject = new DepthTimeObject();
depthTimeObject.setLastTime(new Date());
depthTimeObject.setDepth(depth);
cache.put(key, depthTimeObject);
} else {
depth = ((DepthTimeObject) timeObject).getDepth();
}
return depth;
}
/**
* 近期交易记录
*/
@Override
public Trade trade(String symbol) {
String key = "trade_" + symbol;
Trade trade = new Trade();
TimeObject timeObject = cache.get(key);
if (isRemote(timeObject)) {
trade = remoteDataService.trade(symbol);
if(trade!=null) {
TradeTimeObject tradeTimeObject = new TradeTimeObject();
tradeTimeObject.setLastTime(new Date());
tradeTimeObject.put(symbol, trade.getData());
cache.put(key, tradeTimeObject);
}
} else {
trade = ((TradeTimeObject) timeObject).getTrade();
}
return trade;
}
private boolean isRemote(TimeObject timeObject) {
if (timeObject == null) {
return true;
}
/**
* 判断是否远程 读取数据先完成3秒过期。后期补上非开盘时间不调用。
*/
Date timestamps = timeObject.getLastTime();
/**
* 数据超时时间
*/
// 15秒
//默认3秒
double huobi_data_timeout = Double.valueOf(sysparaService.find("symbol_data_timeout").getValue());
//int timeout = 3;
int timeout = (int) huobi_data_timeout;
if (DateUtils.addSecond(timestamps, timeout).before(new Date())) {
return true;
}
return false;
}
public void setRemoteDataService(DataService remoteDataService) {
this.remoteDataService = remoteDataService;
}
public void setSysparaService(SysparaService sysparaService) {
this.sysparaService = sysparaService;
}
}

View File

@@ -0,0 +1,23 @@
package project.data.internal;
import project.data.model.Depth;
public class DepthTimeObject extends TimeObject {
/**
*
*/
private static final long serialVersionUID = -6508793344391115053L;
private Depth depth;
public Depth getDepth() {
return depth;
}
public void setDepth(Depth depth) {
this.depth = depth;
}
}

View File

@@ -0,0 +1,24 @@
package project.data.internal;
public class HighLow {
private Double high;
private Double low;
public Double getHigh() {
return high;
}
public void setHigh(Double high) {
this.high = high;
}
public Double getLow() {
return low;
}
public void setLow(Double low) {
this.low = low;
}
}

View File

@@ -0,0 +1,117 @@
package project.data.internal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import kernel.util.DateUtils;
import project.data.DataCache;
import project.data.model.Kline;
import project.data.model.Realtime;
public class HighLowHandle {
public static HighLow get(String symbol, int num, int interval) {
List<Realtime> history = bulidNum(DataCache.getRealtimeHistory().get(symbol), num);
HighLow highLow = new HighLow();
if (history == null || history.size() == 0) {
return highLow;
}
Double high = null;
Double low = null;
for (int j = 0; j < history.size(); j++) {
Realtime realtime = history.get(j);
/**
* 停机过久导致的处理
*/
if (realtime.getTs() < DateUtils.addSecond(new Date(), 0 - num * interval).getTime()) {
continue;
}
if (high == null || high < realtime.getClose()) {
high = realtime.getClose();
}
if (low == null || low > realtime.getClose()) {
low = realtime.getClose();
}
}
highLow.setHigh(high);
highLow.setLow(low);
return highLow;
}
public static List<Realtime> bulidNum(List<Realtime> cacheList, int num) {
List<Realtime> list = new ArrayList<Realtime>();
if (cacheList == null) {
return list;
}
if (num > cacheList.size()) {
num = cacheList.size();
}
for (int i = cacheList.size() - num; i < cacheList.size(); i++) {
list.add(cacheList.get(i));
}
return list;
}
public static HighLow getByDay(String symbol, int num) {
KlineTimeObject timeObject = DataCache.getKline(symbol, Kline.PERIOD_1DAY);
HighLow highLow = new HighLow();
if (timeObject == null) {
return highLow;
}
List<Kline> list = timeObject.getKline();
List<Kline> history = new ArrayList<Kline>();
if (num > list.size()) {
num = list.size();
}
for (int i = list.size() - num; i < list.size(); i++) {
history.add(list.get(i));
}
if (history == null || history.size() == 0) {
return highLow;
}
Double high = null;
Double low = null;
for (int j = 0; j < history.size(); j++) {
Kline kline = history.get(j);
/**
* 停机过久导致的处理
*/
if (kline.getTs() < DateUtils.addDay(new Date(), 0 - num).getTime()) {
continue;
}
if (high == null || high < kline.getClose()) {
high = kline.getClose();
}
if (low == null || low > kline.getClose()) {
low = kline.getClose();
}
}
highLow.setHigh(high);
highLow.setLow(low);
return highLow;
}
}

View File

@@ -0,0 +1,10 @@
package project.data.internal;
public interface KlineInitService {
/**
* 初始化K线数据初始化前会删除旧数据
*
* @param symbol 指定产品代码,多个用逗号分割
*/
public void klineInit(String symbols);
}

View File

@@ -0,0 +1,53 @@
package project.data.internal;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import project.data.KlineService;
public class KlineInitServiceImpl implements KlineInitService {
private Logger logger = LogManager.getLogger(this.getClass().getName());
private KlineService klineService;
@Override
public void klineInit(String symbols) {
DelayThread lockDelayThread = new DelayThread(symbols, klineService);
Thread t = new Thread(lockDelayThread);
t.start();
}
public class DelayThread implements Runnable {
private KlineService klineService;
private String symbol;
public void run() {
try {
if (symbol.indexOf(",") == -1) {
klineService.saveInit(symbol);
} else {
String[] symbols = symbol.split(",");
for (int i = 0; i < symbols.length; i++) {
klineService.saveInit(symbols[i]);
}
}
} catch (Exception e) {
logger.error("error:", e);
}
}
public DelayThread(String symbol, KlineService klineService) {
this.symbol = symbol;
this.klineService = klineService;
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
}

View File

@@ -0,0 +1,217 @@
package project.data.internal;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import kernel.util.DateUtils;
import kernel.web.PagedQueryDao;
import project.data.DataCache;
import project.data.KlineService;
import project.data.model.Kline;
import project.data.model.Realtime;
import project.hobi.HobiDataService;
import project.item.ItemService;
import project.syspara.SysparaService;
public class KlineServiceImpl extends HibernateDaoSupport implements KlineService {
private Logger logger = LogManager.getLogger(this.getClass().getName());
private HobiDataService hobiDataService;
private ItemService itemService;
private PagedQueryDao pagedQueryDao;
private SysparaService sysparaService;
private NamedParameterJdbcOperations namedParameterJdbcTemplate;
@Override
public void saveInit(String symbol) {
Map<String, Object> parameters = new HashMap();
parameters.put("symbol", symbol);
this.namedParameterJdbcTemplate.update("DELETE FROM T_KLINE WHERE SYMBOL = :symbol", parameters);
this.bulidInit(symbol, Kline.PERIOD_1MIN);
this.bulidInit(symbol, Kline.PERIOD_5MIN);
this.bulidInit(symbol, Kline.PERIOD_15MIN);
this.bulidInit(symbol, Kline.PERIOD_30MIN);
this.bulidInit(symbol, Kline.PERIOD_60MIN);
this.bulidInit(symbol, Kline.PERIOD_4HOUR);
this.bulidInit(symbol, Kline.PERIOD_1DAY);
this.bulidInit(symbol, Kline.PERIOD_1MON);
this.bulidInit(symbol, Kline.PERIOD_1WEEK);
}
public void bulidInit(String symbol, String line) {
List<Kline> list = hobiDataService.kline(itemService.cacheBySymbol(symbol, true).getSymbol_data(), line, null,
0);
for (int i = 0; i < list.size(); i++) {
this.getHibernateTemplate().saveOrUpdate(list.get(i));
}
KlineTimeObject model = new KlineTimeObject();
Collections.sort(list); // 按时间升序
model.setKline(list);
model.setLastTime(new Date());
DataCache.putKline(symbol, line, model);
}
@Override
public void saveOne(String symbol, String line) {
Realtime realtime = DataCache.getRealtime(symbol);
if (realtime == null) {
logger.error("saveOne error, realtime is null,symbol [" + symbol + "]");
return;
}
Kline lastOne = null;
List<Kline> list = this.find(symbol, line, 1);
if (list.size() > 0) {
lastOne = list.get(0);
}
String key = symbol + "_" + line;
Kline hobiOne = DataCache.getKline_hobi().get(key);
if (hobiOne == null || lastOne == null) {
// 取不到远程数据,直接退出
return;
}
Kline kline = this.bulidKline(realtime, lastOne, hobiOne, line);
kline.setPeriod(line);
this.getHibernateTemplate().save(kline);
KlineTimeObject timeObject = DataCache.getKline(symbol, line);
if (timeObject == null) {
timeObject = new KlineTimeObject();
}
timeObject.getKline().add(kline);
timeObject.setLastTime(new Date());
DataCache.putKline(symbol, line, timeObject);
}
public Kline bulidKline(Realtime realtime, Kline lastOne, Kline hobiOne, String line) {
Kline kline = new Kline();
kline.setSymbol(realtime.getSymbol());
kline.setTs(realtime.getTs());
kline.setOpen(realtime.getOpen());
kline.setHigh(realtime.getHigh());
kline.setLow(realtime.getLow());
kline.setClose(realtime.getClose());
/**
* 新传回来的volume是固定的 需要除以Arith.div(realtime.getVolume(), 倍数)
*/
kline.setVolume(realtime.getVolume());
if (lastOne != null) {
kline.setOpen(lastOne.getClose());
}
int interval = this.sysparaService.find("data_interval").getInteger().intValue() / 1000;
HighLow highLow = null;
switch (line) {
case "1min":
highLow = HighLowHandle.get(realtime.getSymbol(), (60) / interval, interval);
break;
case "5min":
highLow = HighLowHandle.get(realtime.getSymbol(), (60 * 5) / interval, interval);
break;
case "15min":
highLow = HighLowHandle.get(realtime.getSymbol(), (60 * 15) / interval, interval);
break;
case "30min":
highLow = HighLowHandle.get(realtime.getSymbol(), (60 * 30) / interval, interval);
break;
case "60min":
highLow = HighLowHandle.get(realtime.getSymbol(), (60 * 60) / interval, interval);
break;
case "4hour":
highLow = HighLowHandle.get(realtime.getSymbol(), (60 * 60 * 4) / interval, interval);
break;
case "1day":
highLow = HighLowHandle.get(realtime.getSymbol(), (60 * 60 * 24) / interval, interval);
break;
case Kline.PERIOD_1WEEK:
highLow = HighLowHandle.getByDay(realtime.getSymbol(), 7);
break;
case Kline.PERIOD_1MON:
highLow = HighLowHandle.getByDay(realtime.getSymbol(), 30);
break;
}
if (highLow != null && highLow.getHigh() != null) {
kline.setHigh(highLow.getHigh());
}
if (highLow != null && highLow.getLow() != null) {
kline.setLow(highLow.getLow());
}
kline.setVolume(hobiOne.getVolume());
return kline;
}
@Override
public List<Kline> find(String symbol, String line, int pageSize) {
StringBuffer queryString = new StringBuffer(" FROM Kline WHERE 1=1 ");
Map<String, Object> parameters = new HashMap();
queryString.append(" and symbol = :symbol ");
parameters.put("symbol", symbol);
queryString.append(" and period = :period ");
parameters.put("period", line);
queryString.append(" order by ts DESC ");
List<Kline> list = this.pagedQueryDao.pagedQueryHql(0, pageSize, queryString.toString(), parameters)
.getElements();
Collections.sort(list); // 按时间升序
return list;
}
@Override
public void delete(String line, int days) {
Map<String, Object> parameters = new HashMap();
Long ts = DateUtils.addDate(new Date(), days).getTime();
parameters.put("line", line);
parameters.put("ts", ts);
this.namedParameterJdbcTemplate.update("DELETE FROM T_KLINE WHERE PERIOD=:line AND TS < :ts", parameters);
}
public void setHobiDataService(HobiDataService hobiDataService) {
this.hobiDataService = hobiDataService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
public void setPagedQueryDao(PagedQueryDao pagedQueryDao) {
this.pagedQueryDao = pagedQueryDao;
}
public void setSysparaService(SysparaService sysparaService) {
this.sysparaService = sysparaService;
}
public void setNamedParameterJdbcTemplate(NamedParameterJdbcOperations namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.internal;
import java.util.ArrayList;
import java.util.List;
import project.data.model.Kline;
public class KlineTimeObject extends TimeObject {
/**
*
*/
private static final long serialVersionUID = -5777137609729197999L;
private List<Kline> kline=new ArrayList<Kline>();
/**
* @return the kline
*/
public List<Kline> getKline() {
return kline;
}
/**
* @param kline the kline to set
*/
public void setKline(List<Kline> kline) {
this.kline = kline;
}
}

View File

@@ -0,0 +1,22 @@
package project.data.internal;
import java.util.List;
import project.data.model.Realtime;
public class RealtimeTimeObject extends TimeObject{
private static final long serialVersionUID = -597193064229646966L;
List<Realtime> list;
public List<Realtime> getList() {
return list;
}
public void setList(List<Realtime> list) {
this.list = list;
}
}

View File

@@ -0,0 +1,352 @@
package project.data.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import kernel.util.DateUtils;
import project.data.DataCache;
import project.data.DataService;
import project.data.KlineService;
import project.data.job.DataQueue;
import project.data.job.HandleObject;
import project.data.model.Depth;
import project.data.model.Kline;
import project.data.model.Realtime;
import project.data.model.Trade;
import project.data.model.Trend;
import project.item.ItemService;
import project.item.model.Item;
import project.syspara.SysparaService;
public class RemoteDataServiceImpl extends HibernateDaoSupport implements DataService {
private ItemService itemService;
private SysparaService sysparaService;
private KlineService klineService;
@Override
public List<Realtime> realtime(String symbol) {
List<Realtime> list = new ArrayList<Realtime>();
if (symbol.indexOf(",") == -1) {
/**
* 单个symbol
*/
Realtime realtime = DataCache.getRealtime(symbol);
if (realtime != null) {
list.add(realtime);
}
} else {
/**
* 多个symbol用逗号分隔
*/
String[] symbols = symbol.split(",");
for (int i = 0; i < symbols.length; i++) {
String split = symbols[i];
Realtime realtime = DataCache.getRealtime(split);
if (realtime != null) {
list.add(realtime);
}
}
}
return list;
}
@Override
public List<Trend> trend(String symbol) {
TrendTimeObject trendTimeObject = DataCache.getTrend(symbol);
trendTimeObject = this.loadTrend(symbol, trendTimeObject);
if (trendTimeObject != null) {
return trendTimeObject.getTrend();
}
return new ArrayList<Trend>();
}
private TrendTimeObject loadTrend(String symbol, TrendTimeObject trendTimeObject) {
Item item = itemService.cacheBySymbol(symbol, true);
if (trendTimeObject == null || isRemoteTrend(item, trendTimeObject)) {
/**
* 秒
*/
int interval = this.sysparaService.find("data_interval").getInteger().intValue() / 1000;
int num = (24 * 60 * 60) / interval;
List<Trend> list = new ArrayList<Trend>();
/**
* 24小时的历史记录
*/
List<Realtime> history = bulidNum(DataCache.getRealtimeHistory().get(symbol), num);
history = this.take500(history);
if (history.size() > 500) {
Collections.sort(history); // 按时间升序
List<Realtime> history_500 = new ArrayList<Realtime>();
for (int i = 0; i < 500; i++) {
history_500.add(history.get(i));
}
history = history_500;
}
for (int i = 0; i < history.size(); i++) {
Realtime realtime = history.get(i);
Trend trend = bulidTrend(realtime);
list.add(trend);
}
Realtime realtime_last = DataCache.getRealtime(symbol);
if (realtime_last != null) {
list.add(bulidTrend(DataCache.getRealtime(symbol)));
}
trendTimeObject = new TrendTimeObject();
trendTimeObject.setTrend(list);
trendTimeObject.setLastTime(new Date());
DataCache.putTrend(symbol, trendTimeObject);
}
return trendTimeObject;
}
private Trend bulidTrend(Realtime realtime) {
Trend trend = new Trend();
trend.setSymbol(realtime.getSymbol());
trend.setTs(realtime.getTs());
trend.setTrend(realtime.getClose());
trend.setVolume(realtime.getVolume());
trend.setAmount(realtime.getAmount());
return trend;
}
/**
* 按平均频率取500个数据点
*/
private List<Realtime> take500(List<Realtime> history) {
List<Realtime> list = new ArrayList<Realtime>();
int num = history.size() / 500;
if (num <= 0) {
return history;
}
int i = 0;
while (true) {
if (num >= 1.0D) {
if (i % num == 0) {
list.add(history.get(i));
}
} else {
list.add(history.get(i));
}
i++;
if (i >= history.size()) {
break;
}
}
return list;
}
private boolean isRemoteTrend(Item item, TrendTimeObject timeObject) {
/**
* 判断是否远程 读取数据先完成3秒过期。后期补上非开盘时间不调用。
*/
Date timestamps = timeObject.getLastTime();
/**
* 数据超时时间
*/
int timeout = 3;
if (DateUtils.addSecond(timestamps, timeout).before(new Date())) {
return true;
}
return false;
}
private List<Realtime> bulidNum(List<Realtime> cacheList, int num) {
List<Realtime> list = new ArrayList<Realtime>();
if (cacheList == null) {
return list;
}
if (num > cacheList.size()) {
num = cacheList.size();
}
for (int i = cacheList.size() - num; i < cacheList.size(); i++) {
list.add(cacheList.get(i));
}
return list;
}
@Override
public List<Kline> kline(String symbol, String line) {
KlineTimeObject timeObject = DataCache.getKline(symbol, line);
List<Kline> list = new ArrayList<Kline>();
if (timeObject != null) {
list = timeObject.getKline();
}
List<Kline> list_clone = new ArrayList<Kline>();
try {
for (int i = 0; i < list.size(); i++) {
Kline kline = (Kline) list.get(i).clone();
list_clone.add(kline);
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
Realtime realtime = DataCache.getRealtime(symbol);
Kline hobiOne = DataCache.getKline_hobi().get(symbol + "_" + line);
Kline lastOne = null;
if (list != null && list.size() > 0) {
lastOne = list.get(list.size() - 1);
}
if (realtime != null && hobiOne != null && lastOne != null) {
list_clone.add(this.klineService.bulidKline(realtime, lastOne, hobiOne, line));
}
Collections.sort(list_clone); // 按时间升序
return list_clone;
}
@Override
public Depth depth(String symbol) {
DepthTimeObject timeObject = DataCache.getDepth().get(symbol);
this.loadDepth(symbol, timeObject);
if (timeObject != null) {
return timeObject.getDepth();
}
timeObject = new DepthTimeObject();
Depth depth = new Depth();
timeObject.setLastTime(new Date());
timeObject.setDepth(depth);
DataCache.getDepth().put(symbol, timeObject);
return depth;
}
private void loadDepth(String symbol, DepthTimeObject timeObject) {
Item item = itemService.cacheBySymbol(symbol, true);
if (timeObject == null) {
HandleObject handleObject = new HandleObject();
handleObject.setType(HandleObject.type_depth);
handleObject.setItem(item);
DataQueue.add(handleObject);
} else {
if (isRemoteDepth(item, timeObject)) {
HandleObject handleObject = new HandleObject();
handleObject.setType(HandleObject.type_depth);
handleObject.setItem(item);
DataQueue.add(handleObject);
}
}
}
private boolean isRemoteDepth(Item item, DepthTimeObject timeObject) {
// 判断是否远程 读取数据先完成3秒过期。后期补上非开盘时间不调用。
Date timestamps = timeObject.getLastTime();
// 数据超时时间
int timeout = 15;
if (DateUtils.addSecond(timestamps, timeout).before(new Date())) {
return true;
}
return false;
}
/**
* 近期交易记录
*/
@Override
public Trade trade(String symbol) {
TradeTimeObject timeObject = DataCache.getTrade().get(symbol);
this.loadTrade(symbol, timeObject);
if (timeObject != null) {
return timeObject.getTrade();
}
timeObject = new TradeTimeObject();
timeObject.setLastTime(new Date());
DataCache.getTrade().put(symbol, timeObject);
return timeObject.getTrade();
}
private void loadTrade(String symbol, TradeTimeObject timeObject) {
Item item = itemService.cacheBySymbol(symbol, true);
if (timeObject == null) {
HandleObject handleObject = new HandleObject();
handleObject.setType(HandleObject.type_trade);
handleObject.setItem(item);
DataQueue.add(handleObject);
} else {
if (isRemoteTrade(item, timeObject)) {
HandleObject handleObject = new HandleObject();
handleObject.setType(HandleObject.type_trade);
handleObject.setItem(item);
DataQueue.add(handleObject);
}
}
}
private boolean isRemoteTrade(Item item, TradeTimeObject timeObject) {
/**
* 判断是否远程 读取数据先完成3秒过期。后期补上非开盘时间不调用。
*/
Date timestamps = timeObject.getLastTime();
/**
* 数据超时时间
*/
// 15秒
int timeout = 15;
if (DateUtils.addSecond(timestamps, timeout).before(new Date())) {
return true;
}
return false;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
public void setSysparaService(SysparaService sysparaService) {
this.sysparaService = sysparaService;
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
}

View File

@@ -0,0 +1,23 @@
package project.data.internal;
import java.io.Serializable;
import java.util.Date;
public abstract class TimeObject implements Serializable {
private static final long serialVersionUID = -7709770878909783696L;
/**
* 最后读取远程数据时间
*/
private Date lastTime;
public Date getLastTime() {
return lastTime;
}
public void setLastTime(Date lastTime) {
this.lastTime = lastTime;
}
}

View File

@@ -0,0 +1,47 @@
package project.data.internal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import project.data.model.Trade;
import project.data.model.TradeEntry;
public class TradeTimeObject extends TimeObject {
/**
*
*/
private static final long serialVersionUID = -8540786365761455345L;
private Trade trade;
public void put(String symbol, List<TradeEntry> data) {
if (trade == null) {
trade = new Trade();
trade.setSymbol(symbol);
}
trade.getData().addAll(data);
Collections.sort(trade.getData());
if (trade.getData().size() > 50) {
List<TradeEntry> data_50 = new ArrayList<TradeEntry>();
for (int i = 0; i < 50; i++) {
data_50.add(trade.getData().get(i));
}
trade.setData(data_50);
}
}
public Trade getTrade() {
return trade;
}
}

View File

@@ -0,0 +1,25 @@
package project.data.internal;
import java.util.List;
import project.data.model.Trend;
public class TrendTimeObject extends TimeObject {
/**
*
*/
private static final long serialVersionUID = -4078190280148061255L;
private List<Trend> trend;
public List<Trend> getTrend() {
return trend;
}
public void setTrend(List<Trend> trend) {
this.trend = trend;
}
}

View File

@@ -0,0 +1,76 @@
package project.data.job;
import java.util.List;
import kernel.util.ThreadUtils;
import project.data.DataCache;
import project.data.DataDBService;
import project.data.KlineService;
import project.data.model.Kline;
import project.data.model.Realtime;
import project.item.ItemService;
import project.item.model.Item;
public class CleanDataJob {
private DataDBService dataDBService;
private ItemService itemService;
private KlineService klineService;
public void taskJob() {
/**
* 删除过期数据
*/
this.dataDBService.deleteRealtime(-1);
this.dataDBService.updateOptimize("T_REALTIME");
this.klineService.delete(Kline.PERIOD_1MIN, -1);
this.klineService.delete(Kline.PERIOD_5MIN, -2);
this.klineService.delete(Kline.PERIOD_15MIN, -6);
this.klineService.delete(Kline.PERIOD_30MIN, -12);
this.klineService.delete(Kline.PERIOD_60MIN, -24);
this.klineService.delete(Kline.PERIOD_4HOUR, -96);
this.dataDBService.updateOptimize("T_KLINE");
ThreadUtils.sleep(1000);
/**
* 重置实时数据历史缓存
*/
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
List<Realtime> list = this.dataDBService.findRealtimeOneDay(item.getSymbol());
DataCache.getRealtimeHistory().put(item.getSymbol(), list);
DataCache.getKline(item.getSymbol(), Kline.PERIOD_1MIN)
.setKline(this.klineService.find(item.getSymbol(), Kline.PERIOD_1MIN, Integer.MAX_VALUE));
DataCache.getKline(item.getSymbol(), Kline.PERIOD_5MIN)
.setKline(this.klineService.find(item.getSymbol(), Kline.PERIOD_5MIN, Integer.MAX_VALUE));
DataCache.getKline(item.getSymbol(), Kline.PERIOD_15MIN)
.setKline(this.klineService.find(item.getSymbol(), Kline.PERIOD_15MIN, Integer.MAX_VALUE));
DataCache.getKline(item.getSymbol(), Kline.PERIOD_30MIN)
.setKline(this.klineService.find(item.getSymbol(), Kline.PERIOD_30MIN, Integer.MAX_VALUE));
DataCache.getKline(item.getSymbol(), Kline.PERIOD_60MIN)
.setKline(this.klineService.find(item.getSymbol(), Kline.PERIOD_60MIN, Integer.MAX_VALUE));
DataCache.getKline(item.getSymbol(), Kline.PERIOD_4HOUR)
.setKline(this.klineService.find(item.getSymbol(), Kline.PERIOD_4HOUR, Integer.MAX_VALUE));
}
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
public void setDataDBService(DataDBService dataDBService) {
this.dataDBService = dataDBService;
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
}

View File

@@ -0,0 +1,74 @@
package project.data.job;
import java.util.Date;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import kernel.util.ThreadUtils;
import project.data.DataCache;
import project.data.internal.TradeTimeObject;
import project.data.model.Trade;
import project.hobi.HobiDataService;
import project.item.ItemService;
import project.item.model.Item;
public class DataFrequencyServer implements Runnable {
private Logger logger = LogManager.getLogger(this.getClass().getName());
private HobiDataService hobiDataService;
private ItemService itemService;
public void start() {
new Thread(this, "DataFrequencyServer").start();
if (logger.isInfoEnabled())
logger.info("启动DataFrequencyServer");
}
public void run() {
while (true) {
try {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
try {
Item item = item_list.get(i);
this.trade(item);
} catch (Exception e) {
logger.error("trade fail", e);
} finally {
ThreadUtils.sleep(3000);
}
}
} catch (Throwable e) {
logger.error("DataFrequencyServer fail", e);
} finally {
ThreadUtils.sleep(1000 * 10);
}
}
}
private void trade(Item item) {
Trade trade = hobiDataService.tradeDecorator(item.getSymbol_data(), 0);
if (trade != null) {
TradeTimeObject timeObject = DataCache.getTrade().get(item.getSymbol());
if (timeObject == null) {
timeObject = new TradeTimeObject();
}
timeObject.setLastTime(new Date());
timeObject.put(item.getSymbol(), trade.getData());
DataCache.getTrade().put(item.getSymbol(), timeObject);
}
}
public void setHobiDataService(HobiDataService hobiDataService) {
this.hobiDataService = hobiDataService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,26 @@
package project.data.job;
import java.util.concurrent.ConcurrentLinkedQueue;
public class DataQueue {
private static ConcurrentLinkedQueue<HandleObject> WORKING_EVENTS = new ConcurrentLinkedQueue<HandleObject>();
public static void add(HandleObject event) {
try {
WORKING_EVENTS.add(event);
} catch (Throwable e) {
e.printStackTrace();
}
}
public static HandleObject poll() {
HandleObject event = null;
try {
event = WORKING_EVENTS.poll();
} catch (Throwable e) {
e.printStackTrace();
}
return event;
}
}

View File

@@ -0,0 +1,110 @@
package project.data.job;
import java.util.Date;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.task.TaskExecutor;
import kernel.util.ThreadUtils;
import project.data.DataCache;
import project.data.internal.DepthTimeObject;
import project.data.internal.TradeTimeObject;
import project.data.model.Depth;
import project.data.model.Trade;
import project.hobi.HobiDataService;
import project.item.model.Item;
public class DataServer implements Runnable {
private Logger logger = LogManager.getLogger(this.getClass().getName());
private HobiDataService hobiDataService;
private TaskExecutor taskExecutor;
public void start() {
new Thread(this, "DataServer").start();
if (logger.isInfoEnabled())
logger.info("启动DataServer");
}
public void run() {
while (true) {
try {
HandleObject handleObject = DataQueue.poll();
if (handleObject != null) {
this.taskExecutor.execute(new HandleRunner(handleObject, handleObject.getType()));
} else {
ThreadUtils.sleep(50);
}
} catch (Throwable e) {
logger.error("DataServer taskExecutor.execute() fail", e);
}
}
}
public class HandleRunner implements Runnable {
private String type;
private HandleObject handle;
public HandleRunner(HandleObject handle, String type) {
this.handle = handle;
this.type = type;
}
public void run() {
try {
if (HandleObject.type_depth.equals(type)) {
depth(handle);
} else if (HandleObject.type_trade.equals(type)) {
trade(handle);
}
} catch (Throwable t) {
logger.error("HandleRunner run fail ", t);
}
}
private void depth(HandleObject handle) {
Item item = handle.getItem();
Depth depth = hobiDataService.depthDecorator(item.getSymbol_data(), 0);
if (depth != null) {
DepthTimeObject timeObject = new DepthTimeObject();
timeObject.setLastTime(new Date());
timeObject.setDepth(depth);
DataCache.getDepth().put(item.getSymbol(), timeObject);
}
}
private void trade(HandleObject handle) {
Item item = handle.getItem();
Trade trade = hobiDataService.tradeDecorator(item.getSymbol_data(), 0);
if (trade != null) {
TradeTimeObject timeObject = DataCache.getTrade().get(item.getSymbol());
if (timeObject == null) {
timeObject = new TradeTimeObject();
}
timeObject.setLastTime(new Date());
timeObject.put(item.getSymbol(), trade.getData());
DataCache.getTrade().put(item.getSymbol(), timeObject);
}
}
}
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void setHobiDataService(HobiDataService hobiDataService) {
this.hobiDataService = hobiDataService;
}
}

View File

@@ -0,0 +1,160 @@
package project.data.job;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import kernel.util.Arith;
import kernel.util.ThreadUtils;
import project.data.AdjustmentValue;
import project.data.AdjustmentValueCache;
import project.data.DataCache;
import project.data.DataDBService;
import project.data.model.Realtime;
import project.hobi.HobiDataService;
import project.item.ItemService;
import project.item.model.Item;
import project.syspara.SysparaService;
public class GetDataJob implements Runnable {
private Logger logger = LogManager.getLogger(this.getClass().getName());
/**
* 数据接口调用间隔时长(毫秒)
*/
private int interval;
public static boolean first = true;
private SysparaService sysparaService;
private DataDBService dataDBService;
private HobiDataService hobiDataService;
private ItemService itemService;
public void run() {
if (first) {
/**
* data数据保存间隔时长(毫秒)
*/
this.interval = this.sysparaService.find("data_interval").getInteger().intValue();
first = false;
}
while (true) {
try {
this.realtimeHandle();
} catch (Exception e) {
logger.error("run fail", e);
} finally {
ThreadUtils.sleep(this.interval);
}
}
}
private void realtimeHandle() {
/**
* 取到数据
*/
List<Realtime> realtime_list = this.hobiDataService.realtime(0);
for (int i = 0; i < realtime_list.size(); i++) {
try {
Realtime realtime = realtime_list.get(i);
String symbol = realtime.getSymbol();
Double currentValue = AdjustmentValueCache.getCurrentValue().get(symbol);
AdjustmentValue delayValue = AdjustmentValueCache.getDelayValue().get(symbol);
if (delayValue != null) {
/**
* 延时几次
*/
double frequency = Arith.div(Arith.mul(delayValue.getSecond(), 1000.0D), this.interval);
if (frequency <= 1.0D) {
if (currentValue == null) {
AdjustmentValueCache.getCurrentValue().put(symbol, delayValue.getValue());
} else {
AdjustmentValueCache.getCurrentValue().put(symbol,
Arith.add(delayValue.getValue(), currentValue));
}
Item item = this.itemService.cacheBySymbol(symbol, false);
if (item.getAdjustment_value() != AdjustmentValueCache.getCurrentValue().get(symbol)) {
item.setAdjustment_value(AdjustmentValueCache.getCurrentValue().get(symbol));
itemService.update(item);
}
AdjustmentValueCache.getDelayValue().remove(symbol);
} else {
/**
* 本次调整值
*/
double currentValue_frequency = Arith.div(delayValue.getValue(), frequency);
if (currentValue == null) {
AdjustmentValueCache.getCurrentValue().put(symbol, currentValue_frequency);
} else {
AdjustmentValueCache.getCurrentValue().put(symbol,
Arith.add(currentValue, currentValue_frequency));
}
delayValue.setValue(Arith.sub(delayValue.getValue(), currentValue_frequency));
delayValue.setSecond(Arith.sub(delayValue.getSecond(), Arith.div(this.interval, 1000.0D)));
AdjustmentValueCache.getDelayValue().put(symbol, delayValue);
Item item = this.itemService.cacheBySymbol(symbol, false);
if (item.getAdjustment_value() != AdjustmentValueCache.getCurrentValue().get(symbol)) {
item.setAdjustment_value(AdjustmentValueCache.getCurrentValue().get(symbol));
itemService.update(item);
}
}
}
currentValue = AdjustmentValueCache.getCurrentValue().get(realtime.getSymbol());
if (currentValue != null && currentValue != 0) {
realtime.setClose(Arith.add(realtime.getClose(), currentValue));
realtime.setVolume(Arith.add(realtime.getVolume(),
Arith.mul(Arith.div(currentValue, realtime.getClose()), realtime.getVolume())));
realtime.setAmount(Arith.add(realtime.getAmount(),
Arith.mul(Arith.div(currentValue, realtime.getClose()), realtime.getAmount())));
}
Double high = DataCache.getRealtimeHigh().get(symbol);
Double low = DataCache.getRealtimeLow().get(symbol);
if (high == null || realtime.getClose() > high) {
DataCache.getRealtimeHigh().put(symbol, realtime.getClose());
}
if ((low == null || realtime.getClose() < low) && realtime.getClose() > 0) {
DataCache.getRealtimeLow().put(symbol, realtime.getClose());
}
this.dataDBService.saveAsyn(realtime);
} catch (Exception e) {
}
}
}
public void setSysparaService(SysparaService sysparaService) {
this.sysparaService = sysparaService;
}
public void setDataDBService(DataDBService dataDBService) {
this.dataDBService = dataDBService;
}
public void setHobiDataService(HobiDataService hobiDataService) {
this.hobiDataService = hobiDataService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.job;
import project.item.model.Item;
public class HandleObject {
public static String type_depth = "depth";
public static String type_trade = "trade";
/**
*/
private String type;
private Item item;
/**
* K线图的参数line
*/
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
}

View File

@@ -0,0 +1,129 @@
package project.data.job;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import kernel.util.ThreadUtils;
import project.data.DataCache;
import project.data.model.Realtime;
import project.item.ItemService;
import project.item.model.Item;
import project.syspara.SysparaService;
/**
* 最高最低修正
*
*/
public class HighLowHandleJob implements Runnable {
private Logger logger = LogManager.getLogger(this.getClass().getName());
private SysparaService sysparaService;
private ItemService itemService;
/**
* 数据接口调用间隔时长(毫秒)
*/
private int interval;
public static boolean first = true;
@Override
public void run() {
ThreadUtils.sleep(1000 * 60 * 3);
while (true) {
bulidHighLow();
ThreadUtils.sleep(1000 * 60 * 3);
}
}
public void bulidHighLow() {
try {
if (first) {
/**
* data数据保存间隔时长(毫秒)
*/
this.interval = this.sysparaService.find("data_interval").getInteger().intValue() / 1000;
first = false;
}
/**
* 秒
*/
int num = (24 * 60 * 60) / this.interval;
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
try {
/**
* 24小时的历史记录
*/
List<Realtime> history = bulidNum(DataCache.getRealtimeHistory().get(item.getSymbol()), num);
if (history == null || history.size() == 0) {
continue;
}
Double high = null;
Double low = null;
for (int j = 0; j < history.size(); j++) {
Realtime realtime = history.get(j);
if (high == null || high < realtime.getClose()) {
high = realtime.getClose();
}
if ((low == null || low > realtime.getClose()) && realtime.getClose() > 0) {
low = realtime.getClose();
}
}
if (item == null || item.getSymbol() == null) {
logger.error("run fail");
}
if (high != null) {
DataCache.getRealtimeHigh().put(item.getSymbol(), high);
}
if (low != null && low > 0) {
DataCache.getRealtimeLow().put(item.getSymbol(), low);
}
Collections.sort(history);
DataCache.getRealtime24HBeforeOpen().put(item.getSymbol(), history.get(0).getClose());
} catch (Exception e) {
logger.error("run fail", e);
}
}
} catch (Exception e) {
logger.error("run fail", e);
}
}
private List<Realtime> bulidNum(List<Realtime> cacheList, int num) {
List<Realtime> list = new ArrayList<Realtime>();
if (cacheList == null) {
return list;
}
if (num > cacheList.size()) {
num = cacheList.size();
}
for (int i = cacheList.size() - num; i < cacheList.size(); i++) {
list.add(cacheList.get(i));
}
return list;
}
public void setSysparaService(SysparaService sysparaService) {
this.sysparaService = sysparaService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,73 @@
package project.data.job;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import kernel.util.ThreadUtils;
import project.data.DataCache;
import project.data.model.Kline;
import project.hobi.HobiDataService;
import project.item.ItemService;
import project.item.model.Item;
public class KlineCacheJob implements Runnable {
private Logger logger = LogManager.getLogger(this.getClass().getName());
private HobiDataService hobiDataService;
private ItemService itemService;
public void start() {
new Thread(this, "KlineCacheJob").start();
if (logger.isInfoEnabled())
logger.info("启动KlineCacheJob");
}
public void run() {
while (true) {
try {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
this.addCache(item, Kline.PERIOD_1MIN);
this.addCache(item, Kline.PERIOD_5MIN);
this.addCache(item, Kline.PERIOD_15MIN);
this.addCache(item, Kline.PERIOD_30MIN);
this.addCache(item, Kline.PERIOD_60MIN);
this.addCache(item, Kline.PERIOD_4HOUR);
this.addCache(item, Kline.PERIOD_1DAY);
this.addCache(item, Kline.PERIOD_1MON);
this.addCache(item, Kline.PERIOD_1WEEK);
}
} catch (Throwable e) {
logger.error("KlineCacheJob fail", e);
} finally {
ThreadUtils.sleep(1000);
}
}
}
public void addCache(Item item, String line) {
List<Kline> hobikline_list = hobiDataService.kline(item.getSymbol_data(), line, 1, 0);
if (hobikline_list != null && hobikline_list.size() > 0) {
String key = item.getSymbol() + "_" + line;
DataCache.getKline_hobi().put(key, hobikline_list.get(0));
}
ThreadUtils.sleep(2000);
}
public void setHobiDataService(HobiDataService hobiDataService) {
this.hobiDataService = hobiDataService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,9 @@
package project.data.job;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class OffLineEventRejectExecutingHandler implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
}
}

View File

@@ -0,0 +1,38 @@
package project.data.job;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.Assert;
import project.data.model.Realtime;
public class RealtimeQueue {
private static Logger logger = LogManager.getLogger(RealtimeQueue.class);
private static ConcurrentLinkedQueue<Realtime> WORKING_EVENTS = new ConcurrentLinkedQueue<Realtime>();
public static void add(Realtime item) {
Assert.notNull(item, "The item must not be null.");
try {
WORKING_EVENTS.add(item);
} catch (Throwable e) {
logger.error("add() fail : ", e);
}
}
public static int size() {
return WORKING_EVENTS.size();
}
public static Realtime poll() {
Realtime item = null;
try {
item = WORKING_EVENTS.poll();
} catch (Throwable e) {
logger.error("poll() fail : ", e);
}
return item;
}
}

View File

@@ -0,0 +1,55 @@
package project.data.job;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import kernel.util.ThreadUtils;
import project.data.DataDBService;
import project.data.model.Realtime;
public class SaveRealtimeServer implements Runnable {
private Logger logger = LogManager.getLogger(this.getClass().getName());
private DataDBService dataDBService;
public void start() {
new Thread(this, "SaveRealtimeServer").start();
if (logger.isInfoEnabled()) {
logger.info("启动SaveRealtimeServer");
}
}
public void run() {
while (true) {
try {
int size = RealtimeQueue.size();
/**
* 现量轮询一圈
*/
List<Realtime> list = new ArrayList<Realtime>();
for (int i = 0; i < size; i++) {
Realtime item = RealtimeQueue.poll();
list.add(item);
}
if (list.size() > 0) {
dataDBService.saveBatch(list);
}
} catch (Throwable e) {
logger.error(" run fail", e);
} finally {
ThreadUtils.sleep(60 * 1000);
}
}
}
public void setDataDBService(DataDBService dataDBService) {
this.dataDBService = dataDBService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 15分钟K线
*/
public class Kline15MinuteJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_15MIN);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 1天K线
*/
public class Kline1DayJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_1DAY);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 1分钟K线
*/
public class Kline1MinuteJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_1MIN);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 1个月K线
*/
public class Kline1MonJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_1MON);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 1周K线
*/
public class Kline1WeekJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_1WEEK);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 30分钟K线
*/
public class Kline30MinuteJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_30MIN);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 4小时K线
*/
public class Kline4HourJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_4HOUR);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 5分钟K线
*/
public class Kline5MinuteJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_5MIN);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,33 @@
package project.data.klinejob;
import java.util.List;
import project.data.KlineService;
import project.data.model.Kline;
import project.item.ItemService;
import project.item.model.Item;
/**
* 60分钟K线
*/
public class Kline60MinuteJob {
private KlineService klineService;
private ItemService itemService;
public void taskJob() {
List<Item> item_list = itemService.cacheGetAll();
for (int i = 0; i < item_list.size(); i++) {
Item item = item_list.get(i);
klineService.saveOne(item.getSymbol(), Kline.PERIOD_60MIN);
}
}
public void setKlineService(KlineService klineService) {
this.klineService = klineService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
}

View File

@@ -0,0 +1,67 @@
package project.data.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 市场深度数据
*
*/
public class Depth implements Serializable {
/**
*
*/
private static final long serialVersionUID = -6927860235289172991L;
/**
* 产品代码
*/
private String symbol;
/**
* 时间戳
*/
private Long ts;
/**
* 买单
*/
private List<DepthEntry> bids = new ArrayList<DepthEntry>();
/**
* 卖单
*/
private List<DepthEntry> asks = new ArrayList<DepthEntry>();
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Long getTs() {
return ts;
}
public void setTs(Long ts) {
this.ts = ts;
}
public List<DepthEntry> getBids() {
return bids;
}
public void setBids(List<DepthEntry> bids) {
this.bids = bids;
}
public List<DepthEntry> getAsks() {
return asks;
}
public void setAsks(List<DepthEntry> asks) {
this.asks = asks;
}
}

View File

@@ -0,0 +1,34 @@
package project.data.model;
import java.io.Serializable;
/**
* An depth entry consisting of price and amount.
*/
public class DepthEntry implements Serializable {
/**
*
*/
private static final long serialVersionUID = -2177789072570310524L;
private Double price;
private Double amount;
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="project.data.model.Kline" table="T_KLINE">
<id name="id" type="java.lang.String">
<column name="UUID" />
<generator class="uuid.hex" />
</id>
<property name="symbol" type="java.lang.String">
<column name="SYMBOL" />
</property>
<property name="ts" type="long">
<column name="TS" />
</property>
<property name="open" type="double">
<column name="OPEN" />
</property>
<property name="high" type="double">
<column name="HIGH" />
</property>
<property name="low" type="double">
<column name="LOW" />
</property>
<property name="close" type="double">
<column name="CLOSE" />
</property>
<property name="volume" type="double">
<column name="VOLUME" />
</property>
<property name="period" type="java.lang.String">
<column name="PERIOD" />
</property>
</class>
</hibernate-mapping>

View File

@@ -0,0 +1,152 @@
package project.data.model;
import kernel.bo.EntityObject;
/**
* K线图
*/
public class Kline extends EntityObject implements Comparable<Kline>, Cloneable {
public final static String PERIOD_1MIN = "1min";
public final static String PERIOD_5MIN = "5min";
public final static String PERIOD_15MIN = "15min";
public final static String PERIOD_30MIN = "30min";
public final static String PERIOD_60MIN = "60min";
public final static String PERIOD_4HOUR = "4hour";
public final static String PERIOD_1DAY = "1day";
public final static String PERIOD_1MON = "1mon";
public final static String PERIOD_1WEEK = "1week";
/**
* Member Description
*/
private static final long serialVersionUID = -6488478481677363147L;
/**
* 产品代码
*/
private String symbol;
/**
* 时间戳
*/
private Long ts;
/**
* 时间戳的"yyyy-MM-dd HH:mm:ss"格式
*/
private String current_time;
/**
* 开盘价
*/
private Double open;
/**
* 最高价
*/
private Double high;
/**
* 最低价
*/
private Double low;
/**
* 最新价
*/
private Double close;
/**
* 成交量
*/
private Double volume;
/**
* 1min, 5min, 15min, 30min, 60min, 4hour, 1day, 1mon, 1week
*/
private String period;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Long getTs() {
return ts;
}
public void setTs(Long ts) {
this.ts = ts;
getCurrent_time();
}
public Double getClose() {
return close;
}
public void setClose(Double close) {
this.close = close;
}
public Double getOpen() {
return open;
}
public void setOpen(Double open) {
this.open = open;
}
public Double getHigh() {
return high;
}
public void setHigh(Double high) {
this.high = high;
}
public Double getLow() {
return low;
}
public void setLow(Double low) {
this.low = low;
}
public Double getVolume() {
return volume;
}
public void setVolume(Double volume) {
this.volume = volume;
}
public String getCurrent_time() {
return current_time;
}
public void setCurrent_time(String current_time) {
this.current_time = current_time;
}
@Override
public int compareTo(Kline kline) {
if (this.ts > kline.getTs()) {
return 1;
} else if (this.ts < kline.getTs()) {
return -1;
}
return 0;
}
public String getPeriod() {
return period;
}
public void setPeriod(String period) {
this.period = period;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

View File

@@ -0,0 +1,39 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="project.data.model.Realtime" table="T_REALTIME">
<id name="id" type="java.lang.String">
<column name="UUID" />
<generator class="uuid.hex" />
</id>
<property name="symbol" type="java.lang.String">
<column name="SYMBOL" />
</property>
<property name="ts" type="long">
<column name="TS" />
</property>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="open" type="double">
<column name="OPEN" />
</property>
<property name="high" type="double">
<column name="HIGH" />
</property>
<property name="low" type="double">
<column name="LOW" />
</property>
<property name="close" type="double">
<column name="CLOSE" />
</property>
<property name="volume" type="double">
<column name="VOLUME" />
</property>
<property name="amount" type="double">
<column name="AMOUNT" />
</property>
</class>
</hibernate-mapping>

View File

@@ -0,0 +1,199 @@
package project.data.model;
import java.text.DecimalFormat;
import kernel.bo.EntityObject;
import kernel.util.Arith;
import kernel.util.DateUtils;
/**
* 实时价格
*
*/
public class Realtime extends EntityObject implements Comparable<Realtime>, Cloneable {
private static final long serialVersionUID = -4957441549674121537L;
/**
* 产品代码
*/
private String symbol;
/**
* 时间戳
*/
private Long ts;
/**
* 时间戳的"yyyy-MM-dd HH:mm:ss"格式
*/
private String current_time;
/**
* 产品名称
*/
private String name;
/**
* 开盘价
*/
private Double open;
/**
* 最新价
*/
private Double close;
/**
* 最高价
*/
private Double high;
/**
* 最低价
*/
private Double low;
/**
**
* 成交额 金额
*/
private Double volume;
/**
* 成交量 币个数
*/
private Double amount;
/**
* 涨跌幅
*/
private double change_ratio;
public Double getChange_ratio() {
change_ratio = Arith.div(Arith.sub(close, open), open);
change_ratio = Arith.mul(change_ratio, 100);
DecimalFormat df = new DecimalFormat("#.##");
return Double.valueOf(df.format(change_ratio));
}
/**
* change_ratio,asc升序 desc 降序
*/
public String order;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Long getTs() {
return ts;
}
public void setTs(Long ts) {
this.ts = ts;
getCurrent_time();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getOpen() {
return open;
}
public void setOpen(Double open) {
this.open = open;
}
public Double getHigh() {
return high;
}
public void setHigh(Double high) {
this.high = high;
}
public Double getLow() {
return low;
}
public void setLow(Double low) {
this.low = low;
}
public Double getVolume() {
return volume;
}
public void setVolume(Double volume) {
this.volume = volume;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public String getCurrent_time() {
current_time = DateUtils.timeStamp2Date(String.valueOf(ts));
return current_time;
}
public Double getClose() {
return close;
}
public void setClose(Double close) {
this.close = close;
}
@Override
public int compareTo(Realtime realtime) {
if ("asc".equals(order)) {
if (this.getChange_ratio() == realtime.getChange_ratio()) {
return 0;
} else if (this.getChange_ratio() > realtime.getChange_ratio()) {
return 1;
} else if (this.getChange_ratio() < realtime.getChange_ratio()) {
return -1;
}
return 0;
} else if ("desc".equals(order)) {
if (this.getChange_ratio() == realtime.getChange_ratio()) {
return 0;
} else if (this.getChange_ratio() < realtime.getChange_ratio()) {
return 1;
} else if (this.getChange_ratio() > realtime.getChange_ratio()) {
return -1;
}
return 0;
}
if (this.ts > realtime.getTs()) {
return 1;
} else if (this.ts < realtime.getTs()) {
return -1;
}
return 0;
}
public void setOrder(String order) {
this.order = order;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="project.data.model.Symbols" table="T_SYMBOLS">
<id name="id" type="java.lang.String">
<column name="UUID" />
<generator class="uuid.hex" />
</id>
<property name="symbol" type="java.lang.String">
<column name="SYMBOL" />
</property>
<property name="base_currency" type="java.lang.String">
<column name="BASE_CURRENCY" />
</property>
<property name="quote_currency" type="java.lang.String">
<column name="QUOTE_CURRENCY" />
</property>
<property name="price_precision" type="int">
<column name="PRICE_PRECISION" />
</property>
<property name="state" type="java.lang.String">
<column name="STATE" />
</property>
<property name="leverage_ratio" type="double">
<column name="LEVERAGE_RATIO" />
</property>
</class>
</hibernate-mapping>

View File

@@ -0,0 +1,87 @@
package project.data.model;
import kernel.bo.EntityObject;
public class Symbols extends EntityObject {
/**
*
*/
private static final long serialVersionUID = -6358871995039244069L;
/**
* 交易对中的基础币种
*/
private String base_currency;
/**
* 交易对中的报价币种
*/
private String quote_currency;
/**
* 交易对报价的精度(小数点后位数)
*/
private int price_precision;
/**
* 交易对
*/
private String symbol;
/**
* 交易对状态;可能值: [onlineoffline,suspend] online - 已上线offline -
* 交易对已下线不可交易suspend -- 交易暂停
*/
private String state;
/**
* 交易对杠杆最大倍数
*/
private Double leverage_ratio;
public String getBase_currency() {
return base_currency;
}
public void setBase_currency(String base_currency) {
this.base_currency = base_currency;
}
public String getQuote_currency() {
return quote_currency;
}
public void setQuote_currency(String quote_currency) {
this.quote_currency = quote_currency;
}
public int getPrice_precision() {
return price_precision;
}
public void setPrice_precision(int price_precision) {
this.price_precision = price_precision;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Double getLeverage_ratio() {
return leverage_ratio;
}
public void setLeverage_ratio(Double leverage_ratio) {
this.leverage_ratio = leverage_ratio;
}
}

View File

@@ -0,0 +1,48 @@
package project.data.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Trade implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1237970335128424556L;
/**
* 产品代码
*/
private String symbol;
/**
* 时间戳
*/
private Long ts;
private List<TradeEntry> data = new ArrayList<TradeEntry>();
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Long getTs() {
return ts;
}
public void setTs(Long ts) {
this.ts = ts;
}
public List<TradeEntry> getData() {
return data;
}
public void setData(List<TradeEntry> data) {
this.data = data;
}
}

View File

@@ -0,0 +1,83 @@
package project.data.model;
import java.io.Serializable;
import project.hobi.util.DateUtils;
public class TradeEntry implements Comparable<TradeEntry>,Serializable {
/**
*
*/
private static final long serialVersionUID = 7342378765988828212L;
/**
* 以报价币种为单位的成交价格
*/
private Double price;
/**
* 以基础币种为单位的交易量
*/
private Double amount;
/**
* 交易方向“buy” 或 “sell”, “buy” 即买“sell” 即卖
*/
private String direction;
/**
* 时间戳
*/
private Long ts;
/**
* 时间戳的"yyyy-MM-dd HH:mm:ss"格式
*/
private String current_time;
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
this.direction = direction;
}
public Long getTs() {
return ts;
}
public String getCurrent_time() {
current_time = DateUtils.timeStamp2Date(String.valueOf(ts), DateUtils.DF_HHmm);
return current_time;
}
public void setTs(Long ts) {
this.ts = ts;
getCurrent_time();
}
@Override
public int compareTo(TradeEntry model) {
if (this.ts > model.getTs()) {
return -1;
} else if (this.ts < model.getTs()) {
return 1;
}
return 0;
}
}

View File

@@ -0,0 +1,102 @@
package project.data.model;
import kernel.bo.EntityObject;
import project.hobi.util.DateUtils;
/**
* 分时图
*
*/
public class Trend extends EntityObject implements Comparable<Trend> {
private static final long serialVersionUID = -783607185910260696L;
/**
* 产品代码
*/
private String symbol;
/**
* 时间戳
*/
private Long ts;
/**
* 价格(白线)
*/
private Double trend;
/**
* 成交额(以报价币种计量)
*/
private Double volume;
/**
* 成交量(以基础币种计量)
*/
private Double amount;
/**
* 时间戳的"yyyy-MM-dd HH:mm:ss"格式
*/
private String current_time;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Double getTrend() {
return trend;
}
public void setTrend(Double trend) {
this.trend = trend;
}
public Double getVolume() {
return volume;
}
public void setVolume(Double volume) {
this.volume = volume;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public void setCurrent_time(String current_time) {
this.current_time = current_time;
}
public String getCurrent_time() {
current_time = DateUtils.timeStamp2Date(String.valueOf(ts), "HH:mm");
return current_time;
}
public Long getTs() {
return ts;
}
public void setTs(Long ts) {
this.ts = ts;
getCurrent_time();
}
@Override
public int compareTo(Trend trend) {
if (this.ts > trend.getTs()) {
return 1;
} else if (this.ts < trend.getTs()) {
return -1;
}
return 0;
}
}

View File

@@ -0,0 +1,14 @@
package project.hobi;
import java.util.List;
import kernel.web.Page;
public interface AdminContractSymbolsService {
public void saveReload();
public Page pagedQuery(int pageNo, int pageSize, String quote_currency, String base_currency);
public List<String> getQuoteList();
}

View File

@@ -0,0 +1,22 @@
package project.hobi;
import java.util.List;
import java.util.Map;
import kernel.web.Page;
import project.data.model.Symbols;
public interface AdminSymbolsService {
public void saveReload();
public Page pagedQuery(int pageNo, int pageSize, String quote_currency, String base_currency);
public Page pagedQuery(int pageNo, int pageSize);
/**
* 查询报价单位
*/
public Page pagedQueryMap(int pageNo, int pageSize);
}

View File

@@ -0,0 +1,32 @@
package project.hobi;
public class Config {
/**
* API域名
*/
public static String url = "https://api.huobi.pro";
/**
* 所有交易对的最新 Tickers
*/
public static String tickers = "/market/tickers";
/**
* 市场深度数据
*/
public static String depth = "/market/depth";
/**
* 最近市场成交记录
*/
public static String trade = "/market/trade";
/**
* K 线数据(蜡烛图)
*/
public static String kline = "/market/history/kline";
public static String symbols = "/v1/common/symbols";
}

View File

@@ -0,0 +1,54 @@
package project.hobi;
import java.util.List;
import project.data.model.Depth;
import project.data.model.Kline;
import project.data.model.Realtime;
import project.data.model.Symbols;
import project.data.model.Trade;
public interface HobiDataService {
/**
* 实时价格。所有交易对的最新 Tickers
*
*/
public List<Realtime> realtime(int maximum);
/**
* K线
*
* @param period 1day, 1mon, 1week, 1year
*
*/
public List<Kline> kline(String symbol, String period, Integer num, int maximum);
/**
* 市场深度数据20档
*/
public Depth depth(String symbol, int maximum);
/**
* 市场深度数据20档,包装,数据本地化处理
*/
public Depth depthDecorator(String symbol, int maximum);
/**
* 获得近期交易记录
*/
public Trade trade(String symbol, int maximum);
/**
* 获得近期交易记录,包装,数据本地化处理
*/
public Trade tradeDecorator(String symbol, int maximum);
public List<Symbols> symbols();
String getSymbolRealPrize(String symbol);
void putSymbolRealCache(String symbol,String val);
}

View File

@@ -0,0 +1,341 @@
package project.hobi.http;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.ManagedHttpClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultHttpResponseParserFactory;
import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultDnsResolver;
import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
import org.apache.http.io.HttpMessageWriterFactory;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.alibaba.fastjson.JSONObject;
/**
* <p/>
* //请求信息类型MIME每种响应类型的输出普通文本、html 和 XMLjson。允许的响应类型应当匹配资源类中生成的 MIME 类型
* //资源类生成的 MIME 类型应当匹配一种可接受的 MIME 类型。如果生成的 MIME 类型和可接受的 MIME 类型不 匹配,那么将 //生成
* com.sun.jersey.api.client.UniformInterfaceException。例如将可接受的 MIME 类型设置为
* text/xml而将 //生成的 MIME 类型设置为 application/xml。将生成 UniformInterfaceException。
* //代理: new HttpHost("10.0.0.172", 80, "http");
* <p/>
*/
public class HttpHelper {
private static Logger logger = LogManager.getLogger(HttpHelper.class);
private static Map<String, List<Cookie>> cookiesMap = Collections
.synchronizedMap(new HashMap<String, List<Cookie>>());
static private HttpClient httpclient;
private static Map<String, Map<String, String>> globalParam = new HashMap<String, Map<String, String>>(5);
private static Map<String, String> headers = new HashMap<String, String>();
static {
RequestConfig config = RequestConfig.copy(RequestConfig.DEFAULT).setConnectionRequestTimeout(30000)
.setSocketTimeout(40000).build();
SSLContext sslcontext = SSLContexts.createSystemDefault();
HttpMessageWriterFactory<HttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE)).build();
HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
requestWriterFactory, new DefaultHttpResponseParserFactory());
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry,
connFactory, new SystemDefaultDnsResolver());
connManager.setMaxTotal(100);
connManager.setDefaultMaxPerRoute(100);
httpclient = HttpClientBuilder.create().setConnectionManager(connManager).setDefaultRequestConfig(config)
.build();
}
/**
* 通过HTTP协议访问站点并且将返回的数据转换成json对象 注意 对方返回的数据最外层对象必须是单个对象
*
* @param url
* @param param
* @param method
* @return
* @throws IOException
* @throws IOException
*/
public static String getJSONFromHttp(String url, Map<String, Object> param, HttpMethodType method)
throws RuntimeException {
String rs;
switch (method) {
case GET: {
rs = sendGetHttp(url, param);
break;
}
case POST: {
rs = sendPostHttp(url, param, false);
break;
}
default: {
throw new IllegalArgumentException("HTTP访问方式设置有误");
}
}
// logger.debug("return is:" + rs);
return rs == null || "".equals(rs) ? null : rs;
}
public static String sendHttp(String url, Map<String, Object> param, HttpMethodType method)
throws RuntimeException {
switch (method) {
case GET: {
return sendGetHttp(url, param);
}
case POST: {
return sendPostHttp(url, param, false);
}
default:
throw new IllegalArgumentException("参数中的HTTP访问方式有误只支持GET、POST、FILE");
}
}
private static final Pattern paramPat = Pattern.compile("([^&]+)=([^&]+)");
/**
* 发送一个HTTP协议的GET请求
*
* @param url
* @param param
* @return
* @throws IOException
*/
public static String sendGetHttp(String url, Map<String, Object> param) throws RuntimeException {
StringBuilder parmStr = new StringBuilder();
if (null != param && !param.isEmpty()) {
List<NameValuePair> parm = new ArrayList<NameValuePair>(param.size());
for (Map.Entry<String, Object> paramEntity : param.entrySet()) {
Object value = paramEntity.getValue();
if (null != value && !StringUtils.isBlank(value.toString())) {
parm.add(new BasicNameValuePair(paramEntity.getKey(), value.toString()));
}
}
parmStr.append(URLEncodedUtils.format(parm, "UTF-8"));
}
return sendGetHttp(url, parmStr.toString());
}
/**
* 发送一个HTTP协议的GET请求
*
* @param url
* @param param
* @return
* @throws IOException
*/
public static String sendGetHttp(String url, String param) throws RuntimeException {
HttpContext localContext = new BasicHttpContext();
setCookie(localContext, url);
if (!StringUtils.isBlank(param))
url = url + ((url.indexOf("?") > 0) ? "&" + param : "?" + param);
url = appendGlobalParam(url, param);
// logger.debug("远程URL:{}", url);
// 创建HttpGet对象
HttpGet request = new HttpGet(url);
setHeader(request);
String result;
try {
HttpResponse response = httpclient.execute(request, localContext);
result = responseProc(response);
} catch (Exception e) {
logger.error(e.getMessage());
throw new RuntimeException(e);
} finally {
request.reset();
}
return result;
}
private static String appendGlobalParam(String url, Object param) {
for (Map.Entry<String, Map<String, String>> stringMapEntry : globalParam.entrySet()) {
if (url.startsWith(stringMapEntry.getKey())) {
for (Map.Entry<String, String> paramEntry : stringMapEntry.getValue().entrySet()) {
logger.debug("HTTP处理过程发送了参数:" + paramEntry.getKey() + "|" + paramEntry.getValue());
if (param instanceof List)
((List) param).add(new BasicNameValuePair(paramEntry.getKey(), paramEntry.getValue()));
else
url += "&" + paramEntry.getKey() + "=" + paramEntry.getValue();
}
}
}
return url;
}
/**
* 发送一个HTTP协议的POST请求
*
* @param url
* @param param
* @return
* @throws IOException
*/
public static String sendPostHttp(String url, Map<String, Object> param, boolean postTxtBody)
throws RuntimeException {
HttpContext localContext = new BasicHttpContext();
setCookie(localContext, url);
// logger.debug("远程URL:{}", url);
HttpPost request = new HttpPost(url);
List<NameValuePair> parm = new ArrayList<NameValuePair>();
if (null != param && !param.isEmpty())
for (Map.Entry<String, Object> paramEntity : param.entrySet()) {
Object value = paramEntity.getValue();
if (null != value && !StringUtils.isBlank(value.toString())) {
logger.debug("HTTP处理过程发送了参数:" + paramEntity.getKey() + "|" + value);
parm.add(new BasicNameValuePair(paramEntity.getKey(), value.toString()));
}
}
appendGlobalParam(url, parm);
HttpResponse response;
try {
request.setEntity(generyEntity(parm, "UTF-8", postTxtBody));
setHeader(request);
response = httpclient.execute(request, localContext);
} catch (Exception e) {
logger.error(e.getMessage());
throw new RuntimeException(e);
}
String result;
try {
result = responseProc(response);
} catch (IOException e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
} finally {
request.reset();
}
// logger.debug("return is:" + result);
return result;
}
static Pattern urlPrePat = Pattern.compile("https?://([^/]*)?/?");
private static String getUrlPerfix(String url) {
Matcher mat = urlPrePat.matcher(url);
if (mat.find())
return mat.group(1);
return "";
}
private static void setCookie(HttpContext localContext, String url) {
String urlPrefix = getUrlPerfix(url);
CookieStore cookieStore = new BasicCookieStore();
List<Cookie> cookieList = cookiesMap.get(urlPrefix);
if (cookieList != null && cookieList.size() > 0) {
for (Cookie cookie : cookiesMap.get(urlPrefix)) {
cookieStore.addCookie(cookie);
}
localContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
}
}
private static void parseCookie(HttpClientContext context, String url) {
List<Cookie> cookies = context.getCookieStore().getCookies();
String urlPrefix = getUrlPerfix(url);
List<Cookie> oldCookies = cookiesMap.get(urlPrefix);
if (oldCookies != null) {
for (Cookie cookie : cookies) {
for (Cookie oldCookie : oldCookies) {
if (cookie.getName().equals(oldCookie.getName())) {
oldCookies.remove(oldCookie);
oldCookies.add(cookie);
}
}
}
} else
cookiesMap.put(urlPrefix, cookies);
}
private static String responseProc(HttpResponse response) throws IOException {
switch (response.getStatusLine().getStatusCode()) {
case 200: {
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity, "UTF-8");
}
case 302: {
return sendGetHttp(response.getFirstHeader("location").getValue(), "");
}
case 303:
case 304: {
Header[] headers = response.getAllHeaders();
for (Header header : headers) {
logger.debug(header.getName() + " : " + header.getValue());
}
}
default:
throw new HttpResponseException(response.getStatusLine().getStatusCode(),
response.getStatusLine().getReasonPhrase());
}
}
public static void setHeader(HttpRequestBase request) {
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
request.setHeader(headerEntry.getKey(), headerEntry.getValue());
}
}
public static HttpEntity generyEntity(List<NameValuePair> parm, String encode, boolean postTxtBody)
throws Exception {
if (postTxtBody && parm.size() > 0) {
JSONObject paramJson = new JSONObject();
for (NameValuePair nameValuePair : parm) {
paramJson.put(nameValuePair.getName(), nameValuePair.getValue());
}
return (new StringEntity(paramJson.toString(), encode));
} else
return (new UrlEncodedFormEntity(parm, encode));
}
// public static void main(String[] args) {
// byte[] bytes = new byte[1];
// if (bytes instanceof byte[]) {
// System.out.println(1);
// }
// }
}

View File

@@ -0,0 +1,5 @@
package project.hobi.http;
public enum HttpMethodType {
GET, POST, FILE
}

View File

@@ -0,0 +1,90 @@
package project.hobi.internal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import kernel.util.StringUtils;
import kernel.web.Page;
import kernel.web.PagedQueryDao;
import project.data.model.Symbols;
import project.hobi.AdminContractSymbolsService;
import project.hobi.HobiDataService;;
public class AdminContractSymbolsServiceImpl extends HibernateDaoSupport implements AdminContractSymbolsService {
private HobiDataService hobiDataService;
private PagedQueryDao pagedQueryDao;
private JdbcTemplate jdbcTemplate;
@Override
public void saveReload() {
List<Symbols> list = hobiDataService.symbols();
if (list.size() > 0) {
this.delete(this.getAll());
for (int i = 0; i < list.size(); i++) {
this.getHibernateTemplate().saveOrUpdate(list.get(i));
}
}
}
private List<Symbols> getAll() {
List<Symbols> list = (List<Symbols>) this.getHibernateTemplate().find("FROM Symbols ");
return list;
}
@Override
public Page pagedQuery(int pageNo, int pageSize, String quote_currency, String base_currency) {
StringBuffer queryString = new StringBuffer();
queryString.append(" FROM Symbols where 1 = 1 ");
Map<String, Object> parameters = new HashMap();
if (!StringUtils.isNullOrEmpty(quote_currency)) {
queryString.append(" and quote_currency = :quote_currency ");
parameters.put("quote_currency", quote_currency);
} else {
String defaultQuote = jdbcTemplate.queryForObject("SELECT DISTINCT(QUOTE_CURRENCY) FROM T_SYMBOLS LIMIT 1",
String.class);
queryString.append(" and quote_currency =:quote_currency ");
parameters.put("quote_currency", defaultQuote);
}
if (!StringUtils.isNullOrEmpty(base_currency)) {
queryString.append(" and base_currency like:base_currency ");
parameters.put("base_currency", "%" + base_currency + "%");
}
Page page = this.pagedQueryDao.pagedQueryHql(pageNo, pageSize, queryString.toString(), parameters);
return page;
}
public List<String> getQuoteList() {
List<String> result = (List<String>) this.getHibernateTemplate().find("SELECT DISTINCT(obj.quote_currency) FROM Symbols obj");
return result;
}
private void delete(List<Symbols> list) {
this.getHibernateTemplate().deleteAll(list);
}
public void setHobiDataService(HobiDataService hobiDataService) {
this.hobiDataService = hobiDataService;
}
public void setPagedQueryDao(PagedQueryDao pagedQueryDao) {
this.pagedQueryDao = pagedQueryDao;
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}

View File

@@ -0,0 +1,96 @@
package project.hobi.internal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import kernel.util.StringUtils;
import kernel.web.Page;
import kernel.web.PagedQueryDao;
import project.data.model.Symbols;
import project.hobi.AdminSymbolsService;
import project.hobi.HobiDataService;;
public class AdminSymbolsServiceImpl extends HibernateDaoSupport implements AdminSymbolsService {
private HobiDataService hobiDataService;
private PagedQueryDao pagedQueryDao;
@Override
public void saveReload() {
List<Symbols> list = hobiDataService.symbols();
if (list.size() > 0) {
this.delete(this.getAll());
for (int i = 0; i < list.size(); i++) {
this.getHibernateTemplate().saveOrUpdate(list.get(i));
}
}
}
private List<Symbols> getAll() {
List<Symbols> list = (List<Symbols>) this.getHibernateTemplate().find("FROM Symbols ");
return list;
}
@Override
public Page pagedQuery(int pageNo, int pageSize, String quote_currency, String base_currency) {
StringBuffer queryString = new StringBuffer();
queryString.append(" FROM Symbols where 1 = 1 ");
Map<String, Object> parameters = new HashMap();
if (!StringUtils.isNullOrEmpty(quote_currency)) {
queryString.append(" and quote_currency = :quote_currency ");
parameters.put("quote_currency", quote_currency);
}
if (!StringUtils.isNullOrEmpty(base_currency)) {
queryString.append(" and base_currency =:base_currency ");
parameters.put("base_currency", base_currency);
}
Page page = this.pagedQueryDao.pagedQueryHql(pageNo, pageSize, queryString.toString(), parameters);
return page;
}
@Override
public Page pagedQuery(int pageNo, int pageSize) {
StringBuffer queryString = new StringBuffer(" SELECT DISTINCT(QUOTE_CURRENCY) ");
queryString.append(
" FROM T_SYMBOLS WHERE 1 = 1 ");
Map parameters = new HashMap();
Page page = this.pagedQueryDao.pagedQuerySQL(pageNo, pageSize, queryString.toString(), parameters);
return page;
}
@Override
public Page pagedQueryMap(int pageNo, int pageSize) {
StringBuffer queryString = new StringBuffer(" SELECT DISTINCT(QUOTE_CURRENCY) quote_currency ");
queryString.append(
" FROM T_SYMBOLS WHERE 1 = 1 ");
Map parameters = new HashMap();
Page page = this.pagedQueryDao.pagedQuerySQL(pageNo, pageSize, queryString.toString(), parameters);
return page;
}
private void delete(List<Symbols> list) {
this.getHibernateTemplate().deleteAll(list);
}
public void setHobiDataService(HobiDataService hobiDataService) {
this.hobiDataService = hobiDataService;
}
public void setPagedQueryDao(PagedQueryDao pagedQueryDao) {
this.pagedQueryDao = pagedQueryDao;
}
}

View File

@@ -0,0 +1,474 @@
package project.hobi.internal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import kernel.util.Arith;
import kernel.util.StringUtils;
import kernel.util.ThreadUtils;
import project.data.model.Depth;
import project.data.model.DepthEntry;
import project.data.model.Kline;
import project.data.model.Realtime;
import project.data.model.Symbols;
import project.data.model.Trade;
import project.data.model.TradeEntry;
import project.hobi.Config;
import project.hobi.HobiDataService;
import project.hobi.http.HttpHelper;
import project.hobi.http.HttpMethodType;
import project.invest.InvestRedisKeys;
import project.item.ItemService;
import project.item.model.Item;
import project.mall.MallRedisKeys;
public class HobiDataServiceImpl implements HobiDataService {
private Logger logger = LogManager.getLogger(this.getClass().getName());
/**
* 接口调用间隔(毫秒)
*/
private int interval = 100;
private int sleep = 100;
/**
* 最后一次访问接口时间
*/
private volatile Date last_time = new Date();
private volatile boolean lock = false;
private ItemService itemService;
@Override
public List<Realtime> realtime(int maximum) {
List<Realtime> list = new ArrayList<Realtime>();
boolean current_lock = false;
if (lock || (new Date().getTime() - last_time.getTime()) < interval) {
ThreadUtils.sleep(sleep);
if (maximum >= 100) {
logger.warn("---------> 超过 100 次的轮询,未能竞争到查询实时汇率的处理机会,返回空集合。");
return list;
} else {
return realtime(++maximum);
}
} else {
try {
current_lock = true;
lock = true;
Map<String, Object> param = new HashMap<String, Object>();
String result = HttpHelper.getJSONFromHttp(Config.url + Config.tickers, param, HttpMethodType.GET);
JSONObject resultJson = JSON.parseObject(result);
String status = resultJson.getString("status");
if ("ok".equals(status)) {
JSONArray dataArray = resultJson.getJSONArray("data");
Long ts = resultJson.getLongValue("ts");
for (int i = 0; i < dataArray.size(); i++) {
JSONObject realtimeJson = dataArray.getJSONObject(i);
Realtime realtime = new Realtime();
Item item = itemService.cacheBySymbolData(realtimeJson.getString("symbol"));
if (item == null) {
continue;
}
realtime.setSymbol(item.getSymbol());
realtime.setName(item.getName());
realtime.setTs(ts);
realtime.setOpen(realtimeJson.getDouble("open"));
realtime.setClose(realtimeJson.getDouble("close"));
realtime.setHigh(realtimeJson.getDouble("high"));
realtime.setLow(realtimeJson.getDouble("low"));
realtime.setAmount(realtimeJson.getDouble("amount"));
realtime.setVolume(realtimeJson.getDouble("vol"));
list.add(realtime);
}
} else {
logger.error(" realtime()error, resultJson [ " + resultJson.toJSONString() + " ]");
}
} catch (Exception e) {
logger.error("realtime error:", e);
} finally {
if (current_lock) {
lock = false;
last_time = new Date();
}
}
}
return list;
}
@Override
public List<Kline> kline(String symbol, String period, Integer num, int maximum) {
List<Kline> list = new ArrayList<Kline>();
Item item = itemService.cacheBySymbolData(symbol);
if (item == null) {
return list;
}
boolean current_lock = false;
if (lock || (new Date().getTime() - last_time.getTime()) < interval) {
ThreadUtils.sleep(sleep);
if (maximum >= 100) {
return list;
} else {
return this.kline(symbol, period, num, ++maximum);
}
} else {
try {
current_lock = true;
lock = true;
Map<String, Object> param = new HashMap<String, Object>();
param.put("symbol", symbol);
param.put("period", period);
if (num == null) {
if (Kline.PERIOD_1MIN.equals(period)) {
param.put("size", 1440);
}
if (Kline.PERIOD_5MIN.equals(period)) {
param.put("size", 576);
}
if (Kline.PERIOD_15MIN.equals(period)) {
param.put("size", 576);
}
if (Kline.PERIOD_30MIN.equals(period)) {
param.put("size", 576);
}
if (Kline.PERIOD_60MIN.equals(period)) {
param.put("size", 576);
}
if (Kline.PERIOD_4HOUR.equals(period)) {
param.put("size", 576);
}
if (Kline.PERIOD_1DAY.equals(period)) {
param.put("size", 500);
}
if (Kline.PERIOD_1MON.equals(period)) {
param.put("size", 500);
}
if (Kline.PERIOD_1WEEK.equals(period)) {
param.put("size", 500);
}
} else {
param.put("size", num);
}
String result = HttpHelper.getJSONFromHttp(Config.url + Config.kline, param, HttpMethodType.GET);
JSONObject resultJson = JSON.parseObject(result);
String status = resultJson.getString("status");
if ("ok".equals(status)) {
JSONArray dataArray = resultJson.getJSONArray("data");
/**
* 丢弃第一行数据
*/
int start = 1;
if (num != null && num == 1)
start = 0;
for (int i = start; i < dataArray.size(); i++) {
JSONObject realtimeJson = dataArray.getJSONObject(i);
Kline kline = new Kline();
kline.setSymbol(item.getSymbol());
kline.setPeriod(period);
kline.setTs(Long.valueOf(realtimeJson.getString("id") + "000"));
kline.setOpen(realtimeJson.getDouble("open"));
kline.setClose(realtimeJson.getDouble("close"));
kline.setHigh(realtimeJson.getDouble("high"));
kline.setLow(realtimeJson.getDouble("low"));
kline.setVolume(realtimeJson.getDouble("vol"));
list.add(kline);
}
}
} catch (Exception e) {
logger.error("error", e);
} finally {
if (current_lock) {
lock = false;
last_time = new Date();
}
}
}
return list;
}
/**
* 市场深度数据20档,包装,数据本地化处理
*/
public Depth depthDecorator(String symbol, int maximum) {
Depth depth = this.depth(symbol, maximum);
Item item = itemService.cacheBySymbolData(symbol);
item = itemService.cacheBySymbol(item.getSymbol(), false);
if ((depth == null || item.getAdjustment_value() == null || item.getAdjustment_value() == 0) &&
(item.getMultiple() == 0 || item.getMultiple() == 1)) {
return depth;
}
List<DepthEntry> asks = depth.getAsks();
for (int i = 0; i < asks.size(); i++) {
DepthEntry depthEntry = asks.get(i);
/**
* 调整交易量倍数和 行情值
*/
if (item.getMultiple() > 0) {
depthEntry.setAmount(Arith.mul(depthEntry.getAmount(), item.getMultiple()));
}else {
depthEntry.setAmount(depthEntry.getAmount());
}
depthEntry.setPrice(Arith.add(depthEntry.getPrice(), item.getAdjustment_value()));
}
List<DepthEntry> bids = depth.getBids();
for (int i = 0; i < bids.size(); i++) {
DepthEntry depthEntry = bids.get(i);
/**
* 调整交易量倍数和 行情值
*/
if (item.getMultiple() > 0) {
depthEntry.setAmount(Arith.mul(depthEntry.getAmount(), item.getMultiple()));
}else {
depthEntry.setAmount(depthEntry.getAmount());
}
depthEntry.setPrice(Arith.add(depthEntry.getPrice(), item.getAdjustment_value()));
}
return depth;
}
@Override
public Depth depth(String symbol, int maximum) {
boolean current_lock = false;
if (StringUtils.isNullOrEmpty(symbol)) {
return null;
}
if (lock || (new Date().getTime() - last_time.getTime()) < interval) {
ThreadUtils.sleep(sleep);
if (maximum >= 100) {
return null;
} else {
return this.depth(symbol, ++maximum);
}
} else {
try {
current_lock = true;
lock = true;
Map<String, Object> param = new HashMap<String, Object>();
param.put("symbol", symbol);
param.put("type", "step2");
String result = HttpHelper.getJSONFromHttp(Config.url + Config.depth, param, HttpMethodType.GET);
JSONObject resultJson = JSON.parseObject(result);
String status = resultJson.getString("status");
if ("ok".equals(status)) {
JSONObject dataJson = resultJson.getJSONObject("tick");
Long ts = resultJson.getLongValue("ts");
Depth depth = new Depth();
Item item = itemService.cacheBySymbolData(symbol);
if (item == null) {
return null;
}
depth.setSymbol(item.getSymbol());
depth.setTs(ts);
JSONArray bidsArray = dataJson.getJSONArray("bids");
for (int i = 0; i < bidsArray.size(); i++) {
JSONArray object = (JSONArray) bidsArray.get(i);
DepthEntry depthEntry = new DepthEntry();
depthEntry.setPrice(object.getDouble(0));
depthEntry.setAmount(object.getDouble(1));
depth.getBids().add(depthEntry);
}
JSONArray asksArray = dataJson.getJSONArray("asks");
for (int i = 0; i < asksArray.size(); i++) {
JSONArray object = (JSONArray) asksArray.get(i);
DepthEntry depthEntry = new DepthEntry();
depthEntry.setPrice(object.getDouble(0));
depthEntry.setAmount(object.getDouble(1));
depth.getAsks().add(depthEntry);
}
return depth;
}
} catch (Exception e) {
logger.error("error", e);
} finally {
if (current_lock) {
lock = false;
last_time = new Date();
}
}
}
return null;
}
/**
* 获得近期交易记录,包装,数据本地化处理
*/
public Trade tradeDecorator(String symbol, int maximum) {
Trade trade = this.trade(symbol, maximum);
Item item = itemService.cacheBySymbolData(symbol);
item = itemService.cacheBySymbol(item.getSymbol(), false);
if ((trade == null || item.getAdjustment_value() == null || item.getAdjustment_value() == 0) &&
(item.getMultiple() == 0 || item.getMultiple() == 1)) {
return trade;
}
List<TradeEntry> data = trade.getData();
for (int i = 0; i < data.size(); i++) {
TradeEntry tradeEntry = data.get(i);
/**
* 调整交易量倍数和 行情值
*/
if (item.getMultiple() > 0) {
tradeEntry.setAmount(Arith.mul(tradeEntry.getAmount(), item.getMultiple()));
}else {
tradeEntry.setAmount(tradeEntry.getAmount());
}
tradeEntry.setPrice(Arith.add(tradeEntry.getPrice(), item.getAdjustment_value()));
}
return trade;
}
@Override
public Trade trade(String symbol, int maximum) {
boolean current_lock = false;
if (StringUtils.isNullOrEmpty(symbol)) {
return null;
}
if (lock || (new Date().getTime() - last_time.getTime()) < interval) {
ThreadUtils.sleep(sleep);
if (maximum >= 100) {
return null;
} else {
return this.trade(symbol, ++maximum);
}
} else {
try {
current_lock = true;
lock = true;
Map<String, Object> param = new HashMap<String, Object>();
param.put("symbol", symbol);
String result = HttpHelper.getJSONFromHttp(Config.url + Config.trade, param, HttpMethodType.GET);
JSONObject resultJson = JSON.parseObject(result);
String status = resultJson.getString("status");
if ("ok".equals(status)) {
JSONObject dataJson = resultJson.getJSONObject("tick");
Long ts = resultJson.getLongValue("ts");
Trade trade = new Trade();
Item item = itemService.cacheBySymbolData(symbol);
if (item == null) {
return null;
}
trade.setSymbol(item.getSymbol());
trade.setTs(ts);
JSONArray dataArray = dataJson.getJSONArray("data");
for (int i = 0; i < dataArray.size(); i++) {
JSONObject object = dataArray.getJSONObject(i);
TradeEntry tradeEntry = new TradeEntry();
tradeEntry.setTs(object.getLong("ts"));
tradeEntry.setPrice(object.getDouble("price"));
tradeEntry.setAmount(object.getDouble("amount"));
tradeEntry.setDirection(object.getString("direction"));
trade.getData().add(tradeEntry);
}
return trade;
}
} catch (Exception e) {
logger.error("error", e);
} finally {
if (current_lock) {
lock = false;
last_time = new Date();
}
}
}
return null;
}
@Override
public List<Symbols> symbols() {
List<Symbols> list = new ArrayList<Symbols>();
boolean current_lock = false;
if (lock || (new Date().getTime() - last_time.getTime()) < interval) {
return list;
} else {
try {
current_lock = true;
lock = true;
Map<String, Object> param = new HashMap<String, Object>();
String result = HttpHelper.getJSONFromHttp(Config.url + Config.symbols, param, HttpMethodType.GET);
JSONObject resultJson = JSON.parseObject(result);
String status = resultJson.getString("status");
if ("ok".equals(status)) {
JSONArray dataArray = resultJson.getJSONArray("data");
for (int i = 0; i < dataArray.size(); i++) {
JSONObject realtimeJson = dataArray.getJSONObject(i);
Symbols symbols = new Symbols();
symbols.setBase_currency(realtimeJson.getString("base-currency"));
symbols.setQuote_currency(realtimeJson.getString("quote-currency"));
symbols.setLeverage_ratio(realtimeJson.getDouble("leverage-ratio"));
symbols.setPrice_precision(realtimeJson.getIntValue("price-precision"));
symbols.setState(realtimeJson.getString("state"));
symbols.setSymbol(realtimeJson.getString("symbol"));
list.add(symbols);
}
} else {
logger.error(" symbols()error, resultJson [ " + resultJson.toJSONString() + " ]");
}
} catch (Exception e) {
logger.error("error", e);
} finally {
if (current_lock) {
lock = false;
last_time = new Date();
}
}
}
return list;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
@Override
public String getSymbolRealPrize(String symbol) {
return itemService.getRedisHandler().getString(MallRedisKeys.BRUSH_VIRTUAL_CURRENCY_PRICE+symbol);
}
@Override
public void putSymbolRealCache(String symbol, String val) {
itemService.getRedisHandler().setSyncString(MallRedisKeys.BRUSH_VIRTUAL_CURRENCY_PRICE+symbol,val);
}
}

View File

@@ -0,0 +1,58 @@
package project.hobi.util;
import kernel.util.PropertiesUtil;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
*
*/
public abstract class DateUtils {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_TIME_ZONE = PropertiesUtil.getProperty("mall.default.time.zone");
public static final String NORMAL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DFS_MMdd = "MMdd";
public static final String DFS_yyyyMMdd = "yyyyMMdd";
public static final String DFS_yyMMdd = "yyMMdd";
public static final String DF_MMdd = "MM-dd";
public static final String DF_HHmm = "HH:mm";
public static final String DF_MMddHH = "MM-dd HH";
public static final String DF_yyyyMM = "yyyy-MM";
public static final String DF_yyyyMMdd = "yyyy-MM-dd";
public static final String DF_yyyyMMddHH = "yyyy-MM-dd HH";
public static final String DF_yyyyMMddHHmm = "yyyy-MM-dd HH:mm";
public static final String DF_yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss";
public static final String DF_yyyyMMddHHmmssS = "yyyy-MM-dd HH:mm:ss.SSS";
public static final String DF_MMddyyyy = "MM/dd/yyyy";
public static String timeStamp2Date(String seconds, String format) {
if (seconds == null || seconds.isEmpty() || seconds.equals("null")) {
return "";
}
if (format == null || format.isEmpty()) {
format = "yyyy-MM-dd HH:mm:ss";
}
TimeZone timeZone = TimeZone.getTimeZone(DEFAULT_TIME_ZONE);
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(timeZone);
return sdf.format(new Date(Long.valueOf(seconds)));
}
}

View File

@@ -0,0 +1,77 @@
package project.web.admin;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import kernel.exception.BusinessException;
import kernel.util.PropertiesUtil;
import kernel.web.PageActionSupport;
import project.hobi.AdminContractSymbolsService;
@RestController
public class adminContractSymbolsController extends PageActionSupport {
private Logger logger = LogManager.getLogger(adminContractSymbolsController.class);
@Autowired
private AdminContractSymbolsService adminContractSymbolsService;
private final String action = "normal/adminContractSymbolsAction!";
@RequestMapping(action + "list.action")
public ModelAndView list(HttpServletRequest request) {
// 交易对中的报价币种
String quote_currency = request.getParameter("quote_currency");
// 交易对中的基础币种
String base_currency = request.getParameter("base_currency");
String basePath = PropertiesUtil.getProperty("admin_url");
basePath = getPath(request);
this.checkAndSetPageNo(request.getParameter("pageNo"));
this.pageSize = 7;
this.page = this.adminContractSymbolsService.pagedQuery(this.pageNo, pageSize, quote_currency, base_currency);
List<String> quoteList = this.adminContractSymbolsService.getQuoteList();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("pageNo", this.pageNo);
modelAndView.addObject("pageSize", this.pageSize);
modelAndView.addObject("page", this.page);
modelAndView.addObject("basePath", basePath);
modelAndView.addObject("quoteList", quoteList);
modelAndView.setViewName("contract_manage_add_symbols_list");
return modelAndView;
}
private String getPath(HttpServletRequest request) {
return String.format("%s://%s:%s%s", request.getScheme(),request.getServerName()
,request.getServerPort(),request.getContextPath());
}
@RequestMapping(action + "reload.action")
public ModelAndView reload() {
String message = "";
String error = "";
try {
adminContractSymbolsService.saveReload();
message = "数据同步完成";
} catch (BusinessException e) {
error = e.getMessage();
} catch (Exception e) {
logger.error("error ", e);
error = "程序错误";
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", message);
modelAndView.addObject("error", error);
modelAndView.setViewName("contract_manage_add_symbols_list");
return modelAndView;
}
}

View File

@@ -0,0 +1,141 @@
package project.web.api;
import kernel.web.BaseAction;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kernel.exception.BusinessException;
import kernel.util.StringUtils;
import kernel.web.ResultObject;
import project.data.DataService;
import project.data.model.Depth;
import project.data.model.DepthEntry;
import project.item.ItemService;
import project.item.model.Item;
/**
* 市场深度数据 20档深度根据页面取5档或20档
*
*/
@RestController
@CrossOrigin
public class DepthController extends BaseAction {
@Autowired
private DataService dataService;
@Autowired
private ItemService itemService;
@RequestMapping("api/hobi!getDepth.action")
public String getDepth(HttpServletRequest request) {
ResultObject resultObject = new ResultObject();
try {
String symbol = request.getParameter("symbol");
if (StringUtils.isNullOrEmpty(symbol)) {
resultObject.setCode("400");
resultObject.setMsg("[symbol]参数为空");
return JSON.toJSONString(resultObject);
}
// 数据处理
Depth data = this.dataService.depth(symbol);
resultObject.setData(revise(data));
return JSONObject.toJSONString(resultObject);
} catch (BusinessException e) {
resultObject.setCode("402");
resultObject.setMsg(e.getMessage());
return JSONObject.toJSONString(resultObject);
} catch (Throwable e) {
resultObject.setCode("500");
resultObject.setMsg("服务器错误(500)");
return JSONObject.toJSONString(resultObject);
}
}
private Map<String, Object> revise(Depth data) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("symbol", data.getSymbol());
map.put("ts", data.getTs());
Item item = this.itemService.cacheBySymbol(data.getSymbol(), true);
List<Map<String, Object>> asks_list = new ArrayList<Map<String, Object>>();
for (int i = 0; i < data.getAsks().size(); i++) {
DepthEntry depthEntry = data.getAsks().get(i);
Map<String, Object> asks_map = new HashMap<String, Object>();
if (item.getDecimals() == null || item.getDecimals() < 0) {
asks_map.put("price", depthEntry.getPrice());
asks_map.put("amount", depthEntry.getAmount());
} else {
String format = "";
if (item.getDecimals() == 0) {
format = "#";
} else {
format = "#.";
for (int j = 0; j < item.getDecimals(); j++) {
format = format + "#";
}
}
DecimalFormat df = new DecimalFormat(format);
df.setRoundingMode(RoundingMode.FLOOR);// 向下取整
asks_map.put("price", df.format(depthEntry.getPrice()));
asks_map.put("amount", df.format(depthEntry.getAmount()));
}
asks_list.add(asks_map);
}
map.put("asks", asks_list);
List<Map<String, Object>> bids_list = new ArrayList<Map<String, Object>>();
for (int i = 0; i < data.getBids().size(); i++) {
DepthEntry depthEntry = data.getBids().get(i);
Map<String, Object> bids_map = new HashMap<String, Object>();
if (item.getDecimals() == null || item.getDecimals() < 0) {
bids_map.put("price", depthEntry.getPrice());
bids_map.put("amount", depthEntry.getAmount());
} else {
String format = "";
if (item.getDecimals() == 0) {
format = "#";
} else {
format = "#.";
for (int j = 0; j < item.getDecimals(); j++) {
format = format + "#";
}
}
DecimalFormat df = new DecimalFormat(format);
bids_map.put("price", df.format(depthEntry.getPrice()));
bids_map.put("amount", df.format(depthEntry.getAmount()));
}
bids_list.add(bids_map);
}
map.put("bids", bids_list);
return map;
}
}

View File

@@ -0,0 +1,138 @@
package project.web.api;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kernel.exception.BusinessException;
import kernel.util.Arith;
import kernel.util.StringUtils;
import kernel.web.ResultObject;
import project.data.DataService;
import project.data.model.Kline;
import project.hobi.util.DateUtils;
import project.item.ItemService;
import project.item.model.Item;
/**
* K线图
*
*/
@RestController
@CrossOrigin
public class KlineController {
private Logger logger = LogManager.getLogger(KlineController.class);
@Autowired
private DataService dataService;
@Autowired
private ItemService itemService;
@RequestMapping("api/hobi!getKline.action")
public String getKline(HttpServletRequest request) {
ResultObject resultObject = new ResultObject();
String symbol = request.getParameter("symbol");
// 1min, 5min, 15min, 30min, 60min, 4hour, 1day, 1mon, 1week
String line = request.getParameter("line");
try {
if (StringUtils.isNullOrEmpty(symbol)) {
resultObject.setCode("400");
resultObject.setMsg("[symbol]参数为空");
return JSON.toJSONString(resultObject);
}
// 数据处理
List<Kline> data = this.dataService.kline(symbol, line);
if ("1day".equals(line) || "1mon".equals(line) || "1week".equals(line)) {
for (int i = 0; i < data.size(); i++) {
data.get(i).setCurrent_time(
DateUtils.timeStamp2Date(String.valueOf(data.get(i).getTs()), "yyyy-MM-dd"));
}
} else if ("1min".equals(line)) {
for (int i = 0; i < data.size(); i++) {
data.get(i).setCurrent_time(DateUtils.timeStamp2Date(String.valueOf(data.get(i).getTs()), "HH:mm"));
}
} else {
for (int i = 0; i < data.size(); i++) {
data.get(i).setCurrent_time(
DateUtils.timeStamp2Date(String.valueOf(data.get(i).getTs()), "MM-dd HH:mm"));
}
}
resultObject.setData(this.revise(data, line));
} catch (BusinessException e) {
resultObject.setCode("402");
resultObject.setMsg(e.getMessage());
} catch (Throwable e) {
resultObject.setCode("500");
resultObject.setMsg("服务器错误(500)");
logger.error("error:", e);
}
return JSONObject.toJSONString(resultObject);
}
private List<Map<String, Object>> revise(List<Kline> data, String line) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Item item = null;
for (int i = 0; i < data.size(); i++) {
Kline kline = data.get(i);
Map<String, Object> map = new HashMap<String, Object>();
map.put("line", line);
map.put("symbol", kline.getSymbol());
map.put("ts", kline.getTs());
map.put("current_time", kline.getCurrent_time());
if (item == null) {
item = this.itemService.cacheBySymbol(kline.getSymbol(), true);
}
if (item.getDecimals() == null || item.getDecimals() < 0) {
map.put("open", kline.getOpen());
map.put("close", kline.getClose());
map.put("high", kline.getHigh());
map.put("low", kline.getLow());
map.put("volume", kline.getVolume());
} else {
String format = "";
if (item.getDecimals() == 0) {
format = "#";
} else {
format = "#.";
for (int j = 0; j < item.getDecimals(); j++) {
format = format + "#";
}
}
DecimalFormat df = new DecimalFormat(format);
df.setRoundingMode(RoundingMode.FLOOR);// 向下取整
map.put("open", Double.valueOf(df.format(kline.getOpen())));
map.put("close", Double.valueOf(df.format(kline.getClose())));
map.put("high", Double.valueOf(df.format(kline.getHigh())));
map.put("low", Double.valueOf(df.format(kline.getLow())));
if (item.getMultiple() > 0) {
map.put("volume", Double.valueOf(df.format(Arith.mul(kline.getVolume(), item.getMultiple()))));
}else {
map.put("volume", Double.valueOf(df.format(kline.getVolume())));
}
}
list.add(map);
}
return list;
}
}

View File

@@ -0,0 +1,135 @@
package project.web.api;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kernel.exception.BusinessException;
import kernel.util.StringUtils;
import kernel.web.ResultObject;
import project.data.DataService;
import project.data.model.Realtime;
import project.item.ItemService;
import project.item.model.Item;
/**
* 行情实时价格 http接口
*
*/
@RestController
@CrossOrigin
public class RealtimeController {
private Logger logger = LogManager.getLogger(RealtimeController.class);
@Autowired
private DataService dataService;
@Autowired
private ItemService itemService;
@RequestMapping("api/hobi!getRealtime.action")
public String getRealtime(HttpServletRequest request) {
ResultObject resultObject = new ResultObject();
String symbol = request.getParameter("symbol");
// asc升序 desc 降序
String order = request.getParameter("order");
try {
if (StringUtils.isNullOrEmpty(symbol)) {
resultObject.setCode("400");
resultObject.setMsg("[symbol]参数为空");
return JSON.toJSONString(resultObject);
}
// 数据处理
List<Realtime> data = this.dataService.realtime(symbol);
if (!StringUtils.isNullOrEmpty(order)) {
List<Realtime> list_clone = new ArrayList<Realtime>();
for (int i = 0; i < data.size(); i++) {
Realtime realtime = (Realtime) data.get(i).clone();
realtime.setOrder(order);
list_clone.add(realtime);
}
Collections.sort(list_clone);
data = list_clone;
}
resultObject.setData(this.revise(data));
return JSONObject.toJSONString(resultObject);
} catch (BusinessException e) {
resultObject.setCode("402");
resultObject.setMsg(e.getMessage());
return JSONObject.toJSONString(resultObject);
} catch (Throwable e) {
resultObject.setCode("500");
resultObject.setMsg("服务器错误(500)");
logger.error("error:", e);
return JSONObject.toJSONString(resultObject);
}
}
private List<Map<String, Object>> revise(List<Realtime> data) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (int i = 0; i < data.size(); i++) {
Realtime realtime = data.get(i);
Map<String, Object> map = new HashMap<String, Object>();
map.put("symbol", realtime.getSymbol());
map.put("ts", realtime.getTs());
map.put("current_time", realtime.getCurrent_time());
map.put("name", realtime.getName());
map.put("change_ratio", realtime.getChange_ratio());
Item item = this.itemService.cacheBySymbol(realtime.getSymbol(), true);
if (item.getDecimals() == null || item.getDecimals() < 0) {
map.put("open", realtime.getOpen());
map.put("close", realtime.getClose());
map.put("high", realtime.getHigh());
map.put("low", realtime.getLow());
map.put("volume", realtime.getVolume());
map.put("amount", realtime.getAmount());
} else {
String format = "";
if (item.getDecimals() == 0) {
format = "#";
} else {
format = "#.";
for (int j = 0; j < item.getDecimals(); j++) {
format = format + "#";
}
}
DecimalFormat df = new DecimalFormat(format);
df.setRoundingMode(RoundingMode.FLOOR);// 向下取整
map.put("open", df.format(realtime.getOpen()));
map.put("close", df.format(realtime.getClose()));
map.put("high", df.format(realtime.getHigh()));
map.put("low", df.format(realtime.getLow()));
map.put("volume", df.format(realtime.getVolume()));
map.put("amount", df.format(realtime.getAmount()));
}
list.add(map);
}
return list;
}
}

View File

@@ -0,0 +1,112 @@
package project.web.api;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kernel.exception.BusinessException;
import kernel.util.StringUtils;
import kernel.web.BaseAction;
import kernel.web.ResultObject;
import project.data.DataService;
import project.data.model.Trade;
import project.data.model.TradeEntry;
import project.item.ItemService;
import project.item.model.Item;
/**
* 获得近期交易记录 页面保持20条这个只能刷到最新的几条记录。
*
*/
@RestController
@CrossOrigin
public class TradeController extends BaseAction {
@Autowired
private DataService dataService;
@Autowired
private ItemService itemService;
@RequestMapping("api/hobi!getTrade.action")
public String getTrade(HttpServletRequest request) {
ResultObject resultObject = new ResultObject();
try {
String symbol = request.getParameter("symbol");
if (StringUtils.isNullOrEmpty(symbol)) {
resultObject.setCode("400");
resultObject.setMsg("[symbol]参数为空");
return JSON.toJSONString(resultObject);
}
// 数据处理
Trade data = this.dataService.trade(symbol);
if (data != null) {
resultObject.setData(revise(data));
}
return JSONObject.toJSONString(resultObject);
} catch (BusinessException e) {
resultObject.setCode("402");
resultObject.setMsg(e.getMessage());
return JSONObject.toJSONString(resultObject);
} catch (Throwable e) {
resultObject.setCode("500");
resultObject.setMsg("服务器错误(500)");
return JSONObject.toJSONString(resultObject);
}
}
private Map<String, Object> revise(Trade data) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("symbol", data.getSymbol());
map.put("ts", data.getTs());
Item item = this.itemService.cacheBySymbol(data.getSymbol(), true);
List<Map<String, Object>> tradeEntry_list = new ArrayList<Map<String, Object>>();
for (int i = 0; i < data.getData().size(); i++) {
TradeEntry tradeEntry = data.getData().get(i);
Map<String, Object> tradeEntry_map = new HashMap<String, Object>();
tradeEntry_map.put("direction", tradeEntry.getDirection());
tradeEntry_map.put("ts", tradeEntry.getTs());
tradeEntry_map.put("current_time", tradeEntry.getCurrent_time());
if (item.getDecimals() == null || item.getDecimals() < 0) {
tradeEntry_map.put("price", tradeEntry.getPrice());
tradeEntry_map.put("amount", tradeEntry.getAmount());
} else {
String format = "";
if (item.getDecimals() == 0) {
format = "#";
} else {
format = "#.";
for (int j = 0; j < item.getDecimals(); j++) {
format = format + "#";
}
}
DecimalFormat df = new DecimalFormat(format);
df.setRoundingMode(RoundingMode.FLOOR);// 向下取整
tradeEntry_map.put("price", df.format(tradeEntry.getPrice()));
tradeEntry_map.put("amount", df.format(tradeEntry.getAmount()));
}
tradeEntry_list.add(tradeEntry_map);
}
map.put("data", tradeEntry_list);
return map;
}
}

View File

@@ -0,0 +1,112 @@
package project.web.api;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kernel.exception.BusinessException;
import kernel.util.StringUtils;
import kernel.web.ResultObject;
import project.data.DataService;
import project.data.model.Trend;
import project.item.ItemService;
import project.item.model.Item;
/**
* 分时图
*
*/
@RestController
@CrossOrigin
public class TrendController {
private Logger logger = LogManager.getLogger(KlineController.class);
@Autowired
private DataService dataService;
@Autowired
private ItemService itemService;
@RequestMapping("api/hobi!getTrend.action")
public String getTrend(HttpServletRequest request) {
ResultObject resultObject = new ResultObject();
try {
String symbol = request.getParameter("symbol");
if (StringUtils.isNullOrEmpty(symbol)) {
resultObject.setCode("400");
resultObject.setMsg("[symbol]参数为空");
return JSON.toJSONString(resultObject);
}
// 数据处理
List<Trend> data = this.dataService.trend(symbol);
if (data != null) {
resultObject.setData(revise(data));
}
} catch (BusinessException e) {
resultObject.setCode("402");
resultObject.setMsg(e.getMessage());
} catch (Throwable e) {
resultObject.setCode("500");
resultObject.setMsg("服务器错误(500)");
logger.error("error:", e);
}
return JSONObject.toJSONString(resultObject);
}
private List<Map<String, Object>> revise(List<Trend> data) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Item item = null;
for (int i = 0; i < data.size(); i++) {
Trend trend = data.get(i);
Map<String, Object> map = new HashMap<String, Object>();
map.put("symbol", trend.getSymbol());
map.put("ts", trend.getTs());
map.put("current_time", trend.getCurrent_time());
if (item == null) {
item = this.itemService.cacheBySymbol(trend.getSymbol(), true);
}
if (item.getDecimals() == null || item.getDecimals() < 0) {
map.put("trend", trend.getTrend());
map.put("volume", trend.getVolume());
map.put("amount", trend.getAmount());
} else {
String format = "";
if (item.getDecimals() == 0) {
format = "#";
} else {
format = "#.";
for (int j = 0; j < item.getDecimals(); j++) {
format = format + "#";
}
}
DecimalFormat df = new DecimalFormat(format);
df.setRoundingMode(RoundingMode.FLOOR);// 向下取整
map.put("trend", df.format(trend.getTrend()));
map.put("volume", df.format(trend.getVolume()));
map.put("amount", df.format(trend.getAmount()));
}
list.add(map);
}
return list;
}
}