注:该项目使用的 IDE 是 Visual Studio 2010,采用通讯库为 WinSock2.h,如果使用 Linux 系统进行检测则会编译失败,使用其他 IDE 有可能发生未知异常,所以我将自己电脑上运行的一部分运行状况截图。
程序的主要部分,即为项目“服务器”,采用 Windows Socket 借口,使用虚拟地址“127.0.0.1”,利用一个 while 循环来实现与多个客户端连接,每次循环连接成功后都会对当前客户端开启一个新的线程,所有客户端连接成功的 socket 都储存在全局变量 m_Server 数组里。
用户部分,即为项目“普通客户端”,普通客户端开启两个线程,一个用来发送订单,一个用来接受订单。用户开启客户端会有指令来操作一系列交易。客户端与服务器通过 recv 函数与 send 函数来互相发送 FIX 协议信息。
MonitorClient 用来监测每个连接的用户进行的一系列操作。
RandomClient 用来模拟实际的交易所,该客户端会随机发送买卖订单给服务器。
股票类有以下几个属性:
averagePrice(当前价格)
start_price(开盘价格)
id(股票代码)
stock_name(股票名称)
end_price(闭盘价格)
max_price(最高价格)
min_price(最低价格)
成员函数:
每个属性对应的获取接口
updatePrice(更新最高价格与最低价格)
关于 Order 对象有以下几个属性:
Order_id(每个订单独有,由系统自动生成)
stock_name 股票名称
amount (交易数量)
side(买方卖方)
avg_price(当前平均交易价格)
give_price(订单产生时出价)
execute_amount(已经交易的数量)
infomation(具体的交易情况)
成员函数:
各个属性的获取接口
writeResult(string opposite_name, int ex_amount, double ex_price) 该函数作用是将交易双方的一系列交易信息(交易数量、价格)写入对应的 股票 record.txt 中
关于 FixMessage 类有以下属性:
side(买方卖方,tag=“54”)
average_price(平均价格,tag=“6”)
price(价格,tag=“44”)
filled_amount(已经交易数量,tag=“14”)
order_id(订单号,tag=“11”)
user_name(用户名,tag=“49”)
open_amount(剩余未交易数量,tag=“151”)
amount(总数,tag=“38”)
stock_name(股票名称,tag=“1”)
order_type(订单消息种类(新订单、取消、拒绝),tag=“35”)
execution type(执行种类,tag=“150”)
order_status(订单状态(新订单,部分交易,全部交易,取消), tag=“39”)
成员函数:
各个属性的获取接口
在构造函数中对获取的字符串进行解析,用“;”分割出各个 tag
在服务器端程序中构造一个子线程共享的 Order 队列,对于每一个线程提出的要求,都要去 Order 队列里进行匹配,所以 Order 队列应对子线程保持互斥。这里使用 queue_section 全局关键段来达到互斥,给 orderList“上锁”。
下列是全局的订单队列:
buyOrderList:买方订单,按照价格由高到低排序,出价高的优先进行交易
SaleOrderList:卖方订单,按照价格由低到高排序,要价低的优先进行交易
endBuyOrder:已经结束或被取消的买方订单
endSaleOrder:已经结束或被取消的卖方订单
Order 进入后,先辨别是买方 Order 还是卖方 Order 进行分流,其次判断价格是否在市场内,不在的话插入队列结束,在的话直接进行匹配完成交易。 匹配细节:优先匹配最令客户满意的 Order,再进行数量匹配,出现下列三种情况:
己方订单数量大于对方订单数量,则对方订单全部交易,己方继续与队列中下一个订单进行比较,循环直到不能再交易或全部交易。不能交易时如果未交易完,则放入队列 buyOrderList 或 SaleOrderList
己方订单数量等于对方订单数量,双方均全部交易
己方订单数量小于对方订单数量,己方全部交易,对方部分交易不出队列,直接结束
用户发出取消操作,检查 buyOrderList、SaleOrderList,如果发现要取消的订单 , 则 将其 放 入 endBuyOrder 或 endSaleOrder , 如 果 在 endBuyOrder 、endSaleOrder 中找到该订单,则拒绝取消操作,因为该订单已被交易完毕。
网友评论