订单类
package comm;
public class order {
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public Long getOrderTs() {
return orderTs;
}
public void setOrderTs(Long orderTs) {
this.orderTs = orderTs;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Integer getVolume() {
return volume;
}
public void setVolume(Integer volume) {
this.volume = volume;
}
public boolean getDirection() {
return direction;
}
public void setDirection(boolean direction) {
this.direction = direction;
}
public order(){
this.setOrderTs(System.currentTimeMillis());
}
public order(Long orderId){
if (orderId != null && orderId > 0){
this.setOrderId(orderId);
}else {
this.setOrderId(new Long(0));
}
this.setOrderTs(System.currentTimeMillis());
}
public order(order other){
this.setVolume(other.volume);
this.setPrice(other.price);
this.setOrderId(other.orderId);
this.setDirection(other.direction);
this.setOrderTs(System.currentTimeMillis());
}
private boolean direction;//true --> bid, false --> ask
private Long orderId;
private Long orderTs;
private Integer price;
private Integer volume;
}
成交类
package comm;
public class trade extends order{
public trade(Long tradeId, order o){
this.setVolume(o.getVolume());
this.setPrice(o.getPrice());
this.setDirection(o.getDirection());
this.setOrderId(o.getOrderId());
this.setOrderTs(o.getOrderTs());
this.setTradeId(tradeId);
this.setTradeTs(System.currentTimeMillis());
}
public trade(){
this.setTradeTs(System.currentTimeMillis());
}
public trade(Long tradeId, Integer price, Integer volume, boolean direction, Long orderTs, Long orderId){
this.setTradeId(tradeId);
this.setPrice(price);
this.setVolume(volume);
this.setDirection(direction);
this.setOrderTs(orderTs);
this.setOrderId(orderId);
this.setTradeTs(System.currentTimeMillis());
}
public Long getTradeId() {
return tradeId;
}
public void setTradeId(Long tradeId) {
this.tradeId = tradeId;
}
public Long getTradeTs() {
return tradeTs;
}
public void setTradeTs(Long tradeTs) {
this.tradeTs = tradeTs;
}
private Long tradeId;
private Long tradeTs;
}
报单工具
package quota;
import comm.order;
import match.MatchMng;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
public class Quota {
private MatchMng match;
private AtomicBoolean start = new AtomicBoolean(false);
private AtomicLong orderId = new AtomicLong(1);
public Quota(MatchMng match) {
this.match = match;
}
public void start(){
if(start.compareAndSet(false,true)){
System.out.println("start biding...");
new Timer("bid").scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
order o = new order(orderId.getAndIncrement());
Random rand = new Random(System.currentTimeMillis());
o.setPrice(rand.nextInt(1000));
o.setVolume(rand.nextInt(1000));
o.setDirection(true);
match.Bid(o);
}
}, 1000, 5);
System.out.println("start ask...");
new Timer("ask").scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
order o = new order(orderId.getAndIncrement());
Random rand = new Random(System.currentTimeMillis() + 1000);
o.setPrice(rand.nextInt(1000));
o.setVolume(rand.nextInt(1000));
o.setDirection(false);
match.Ask(o);
}
}, 1000, 5);
}
}
}
撮合
package match;
import comm.order;
import comm.trade;
import java.util.LinkedList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.Thread.sleep;
public class MatchMng {
private LinkedList> bid = new LinkedList<>();
private LinkedList> ask = new LinkedList<>();
private final LinkedList input = new LinkedList<>();
private ReentrantLock lockInput = new ReentrantLock();
private final LinkedList outputTrades = new LinkedList<>();
private ReentrantLock lockOutput = new ReentrantLock();
private final AtomicLong tradeId = new AtomicLong(1);
private final AtomicBoolean start = new AtomicBoolean(false);
public void start(){
if (start.compareAndSet(false, true)){
sender.setName("sender");
processor.setName("processor");
sender.start();
processor.start();
new Timer("level").scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
System.out.printf("Bid levels:[%d], Ask levels:[%d]%n",
bid.size(), ask.size());
}
}, 1000, 500);
}
}
private Thread sender = new Thread(()->{
int emptyTimes = 0;
while (true) {
try {
lockOutput.lock();
trade t = outputTrades.pollFirst();
lockOutput.unlock();
if (t != null) {
sendTrade(t);
emptyTimes = 0;
} else {
if (emptyTimes++ < 5) {
sleep(5);
} else if (emptyTimes > 20){
sleep(20);
} else {
sleep(emptyTimes);
}
}
} catch (InterruptedException e){
e.printStackTrace();
}
}
});
private Thread processor = new Thread(()->{
int emptyTimes = 0;
while (true){
try {
lockInput.lock();
order o = input.pollFirst();
lockInput.unlock();
if (o != null) {
process(bid, ask, o);
} else {
if (emptyTimes < 5) {
emptyTimes++;
} else if (emptyTimes >= 20) {
emptyTimes++;
sleep(20);
} else {
emptyTimes++;
sleep(emptyTimes);
}
}
} catch (InterruptedException e){
e.printStackTrace();
}
}
});
public boolean Bid(order o){
if (!o.getDirection()){
return false;
}
System.out.printf("bid order:[%d]%n", o.getOrderId());
try {
lockInput.lock();
input.addLast(o);
}finally {
lockInput.unlock();
}
return true;
}
public boolean Ask(order o){
if (o.getDirection()){
return false;
}
System.out.printf("ask order:[%d]%n", o.getOrderId());
try{
lockInput.lock();
input.addLast(o);
}finally {
lockInput.unlock();
}
return true;
}
private void sendTrade(trade t){
System.out.printf("TradeID:[%d], OrderID:[%d], Direction:[%b], OrderTs:[%d], Price:[%d],Volume:[%d]%n",
t.getTradeId(), t.getOrderId(), t.getDirection(), t.getOrderTs(), t.getPrice(), t.getVolume());
}
private void insertOrder(LinkedList> orders, order o){
for (int i=0; i
if (orders.get(i).getFirst().getPrice() == o.getPrice()){
orders.get(i).addLast(o);
return;
}
if (orders.get(i).getFirst().getPrice() > o.getPrice()){
LinkedList list = new LinkedList<>();
list.add(o);
orders.add(i, list);
return;
}
}
LinkedList list = new LinkedList<>();
list.add(o);
orders.addLast(list);
}
//返回是否要继续吃单子
private boolean deleteOrder(LinkedList> orders, order o, int idx){
try {
lockOutput.lock();
LinkedList list = orders.get(idx);
while (list.size() > 0 && o.getVolume() > 0){
if (list.getFirst().getVolume() < o.getVolume()){
o.setVolume(o.getVolume() - list.getFirst().getVolume());
trade t1 = new trade(tradeId.getAndIncrement(), list.removeFirst());
trade t2 = new trade(tradeId.getAndIncrement(),
o.getPrice(), t1.getVolume(), o.getDirection(),o.getOrderTs(),o.getOrderId());
outputTrades.add(t1);
outputTrades.add(t2);
} else if (list.getFirst().getVolume() > o.getVolume()){
list.getFirst().setVolume(list.getFirst().getVolume() - o.getVolume());
trade t2 = new trade(tradeId.getAndIncrement(), o);
trade t1 = new trade(tradeId.getAndIncrement(),
o.getPrice(), t2.getVolume(),
list.getFirst().getDirection(), list.getFirst().getOrderTs(), list.getFirst().getOrderId());
outputTrades.add(t1);
outputTrades.add(t2);
o.setVolume(0);
return false;
} else {
trade t1 = new trade(tradeId.getAndIncrement(), o);
trade t2 = new trade(tradeId.getAndIncrement(),list.removeFirst());
outputTrades.add(t1);
outputTrades.add(t2);
o.setVolume(0);
}
}
//吃完一档
if (list.size() == 0){
orders.remove(idx);
}
if (o.getVolume() == 0){
return false;
}
return true;
}finally {
lockOutput.unlock();
}
}
private void process(LinkedList> bid, LinkedList> ask, order o){
if (o.getDirection()){
if (ask.isEmpty() || (ask.getFirst().getFirst().getPrice() > o.getPrice())){
insertOrder(bid, o);
} else{
while (!ask.isEmpty() && deleteOrder(ask, o, 0));
if (o.getVolume() > 0){
insertOrder(bid, o);
}
}
} else {
if (bid.isEmpty() || (bid.getLast().getFirst().getPrice() < o.getPrice())){
insertOrder(ask, o);
}else {
while (!bid.isEmpty() && deleteOrder(bid, o, bid.size()-1));
if (o.getVolume() > 0){
insertOrder(ask, o);
}
}
}
}
}
控制类
import match.MatchMng;
import quota.Quota;
public class Matching {
public static void main(String[] args){
MatchMng matchMng = new MatchMng();
Quota quota = new Quota(matchMng);
quota.start();
matchMng.start();
}
}