【交易】撮合交易
试利用单链表作为存放委托的数据结构(撮合队列),编写一模拟股票交易的程序,该程序有以下几个功能:
1. 委托申请:
输入:每个委托包括四个数据项,股票编码( 4 位数字)、价格(浮点数)、数量(整数)、买 / 卖( B/S )
输出:
a. 程序为每个委托产生一个唯一的序号( d ),该序号从 1 开始;
b. 每笔成交包括:成交价格( %6.1f )、成交量( %4d )、新的委托序号( d )、匹配的委托序号( d )。
2. 查询未成交的委托:
输入:股票编码
输出:按撮合队列中委托的顺序,分别输出该股票未成交的委托,每个输出的委托包括:委托序号( d )、 股票编码 ( d
#include <stdio.h>
#include <stdlib.h>
int count;
#define MAX_DATE_NUM 10000
#define MAX_STOCK_NUM 10000
//买/卖手笔数据
struct date
{
int orderid;
int stockid;
float price;
int quantity;
int bs;
struct date *next;
};
typedef struct date DATE;
typedef struct date *PDATE;
//交易仓数据
struct stock
{
int stockid;
struct stock *next;
struct date *b;
struct date *s;
};
typedef struct stock STOCK;
typedef struct stock *PSTOCK;
PDATE adress[MAX_DATE_NUM];
PSTOCK pStockArr[MAX_STOCK_NUM];
PSTOCK home;
/**
* @brief 处理链表设置
* @param p0 PDATE链表头
* @param stockid 买/卖单ID
* @param price 买/卖出价
* @param bs 买/卖标志
* @param quantity 笔数
*/
PDATE setnew(PDATE p0, int stockid, float price, int quantity, int bs)
{
PDATE p;
p = (PDATE) malloc (sizeof(DATE));
p->bs = bs;
if(p0 != NULL)
{
p->next = p0->next;
p0->next = p;
}
else
{
p->next = NULL;
}
p->orderid = count++;
adress[p->orderid] = p;
p->price = price;
p->quantity = quantity;
p->stockid = stockid;
return p;
}
PSTOCK setnewstock(int stockid)
{
PSTOCK p = NULL;
p = (PSTOCK)malloc(sizeof(STOCK));
pStockArr[stockid] = p;
p->b = NULL;
p->s = NULL;
p->stockid = stockid;
return p;
}
/**
* @brief 交易仓插入买/卖单
* @param home 链表头
* @param stockid 买/卖单ID
* @param price 买/卖出价
* @param bs 买/卖标志
* @param quantity 笔数
*/
PSTOCK insert(PSTOCK home, int stockid, float price, int bs, int quantity)
{
PDATE p2;
if(pStockArr[stockid] == NULL)
setnewstock(stockid);
PDATE p1 = NULL;
if(bs == 1) //??toС
{
p1 = pStockArr[stockid]->b;
if(p1 == NULL)
{
pStockArr[stockid]->b = setnew(NULL, stockid, price, quantity, bs);
return pStockArr[stockid];
}
else
{
while(1)
{
if(p1->price < price)
{
p2 = setnew(p1, p1->stockid, p1->price, p1->quantity, p1->bs);
p1->bs = bs;
int tempid;
tempid = p2->orderid;
p2->orderid = p1->orderid;
p1->orderid = tempid;
p1->price = price;
p1->quantity = quantity;
adress[p2->orderid] = p2;
adress[p1->orderid] = p1;
return pStockArr[stockid];
}
else if(p1->next == NULL)
{
setnew(p1, stockid, price, quantity, bs);
return pStockArr[stockid];
}
p1 = p1->next;
}
}
}
else//Сto??
{
p1 = pStockArr[stockid]->s;
if(p1 == NULL)
{
pStockArr[stockid]->s = setnew(NULL, stockid, price, quantity, bs);
return pStockArr[stockid];
}
else
{
while(1)
{
if(p1->price > price)
{
p2 = setnew(p1, p1->stockid, p1->price, p1->quantity, p1->bs);
p1->bs = bs;
int tempid;
tempid = p2->orderid;
p2->orderid = p1->orderid;
p1->orderid = tempid;
p1->price = price;
p1->quantity = quantity;
adress[p2->orderid] = p2;
adress[p1->orderid] = p1;
return pStockArr[stockid];
}
else if(p1->next == NULL)
{
setnew(p1, stockid, price, quantity, bs);
return pStockArr[stockid];
}
p1 = p1->next;
}
}
}
}
/**
* @brief 删除节点
* @param p 买/卖单链表
* @return PDATE 删减后的买/卖单链表
*/
PDATE del(PDATE p)
{
adress[p->orderid] = NULL;
if(p->next == NULL)
{
PSTOCK p0 = home;
p0 = pStockArr[p->stockid];
PDATE p1 = NULL;
if(p->bs == 1)
{
p1 = p0->b;
if(p1 == p)
{
p0->b = NULL;
free(p);
}
else
{
while(p1->next != p)
p1 = p1->next;
p1->next = NULL;
free(p);
}
}
else
{
p1 = p0->s;
if(p1 == p)
{
p0->s = NULL;
free(p);
}
else
{
while(p1->next != p)
p1 = p1->next;
p1->next = NULL;
free(p);
}
}
return NULL;
}
PDATE pn = p->next;
p->bs = pn->bs;
p->next = pn->next;
p->orderid = pn->orderid;
p->price = pn->price;
p->quantity = pn->quantity;
p->stockid = pn->stockid;
free(pn);
adress[p->orderid] = p;
return p;
}
/**
* @brief 撮合交易
* @param p 交易仓连接
* @param bs 买/卖标志
* @param quantity 数量
* @return 0
*/
int marriedDeal(PSTOCK p, int bs, int quantity)
{
printf("orderid: %04d\n", count - 1);
PDATE ps, pb;
ps = p->s;
pb = p->b;
if(!(ps != NULL && pb != NULL))
goto z;
while(ps->price <= pb->price) //deal--price: 10.5 quantity:1000 sellorder:0008 buyorder:0004
{
if(ps->quantity > pb->quantity)
{
if(bs == 1)
printf("deal--price:%6.1f quantity:%4d buyorder:%04d sellorder:%04d\n", (ps->price + pb->price) / 2.0, pb->quantity, pb->orderid, ps->orderid);
else
printf("deal--price:%6.1f quantity:%4d sellorder:%04d buyorder:%04d\n", (ps->price + pb->price) / 2.0, pb->quantity, ps->orderid, pb->orderid);
ps->quantity -= pb->quantity;
pb = del(pb);
}
else if(ps->quantity < pb->quantity)
{
if(bs == 1)
printf("deal--price:%6.1f quantity:%4d buyorder:%04d sellorder:%04d\n", (ps->price + pb->price) / 2.0, ps->quantity, pb->orderid, ps->orderid);
else
printf("deal--price:%6.1f quantity:%4d sellorder:%04d buyorder:%04d\n", (ps->price + pb->price) / 2.0, ps->quantity, ps->orderid, pb->orderid);
pb->quantity -= ps->quantity;
ps = del(ps);
}
else
{
if(bs == 1)
printf("deal--price:%6.1f quantity:%4d buyorder:%04d sellorder:%04d\n", (ps->price + pb->price) / 2.0, ps->quantity, pb->orderid, ps->orderid);
else
printf("deal--price:%6.1f quantity:%4d sellorder:%04d buyorder:%04d\n", (ps->price + pb->price) / 2.0, ps->quantity, ps->orderid, pb->orderid);
pb = del(pb);
ps = del(ps);
}
if(ps == NULL || pb == NULL) break;
}
z:
if(quantity == 0)
{
PDATE pdel = ((bs == 1) ? p->b : p->s);
while(pdel != NULL)
if(pdel->quantity == 0)
break;
else
pdel = pdel->next;
if(pdel != NULL)
del(pdel);
}
return 0;
}
/**
* @brief 列出订单
* @param p 货物链表
*
* @return 无
*/
void listOrders(PSTOCK p)//orderid: 0005, stockid:0003, price: 10.0, quantity: 300, b/s: b
{
PDATE pt;
pt = p->b;
printf("buy orders:\n");
while(pt != NULL)
{
printf("orderid: %04d, stockid:%04d, price: %6.1f, quantity: %4d, b/s: %c\n", pt->orderid, pt->stockid, pt->price, pt->quantity, pt->bs == 1 ? 'b' : 's');
pt = pt->next;
}
pt = p->s;
printf("sell orders:\n");
while(pt != NULL)
{
printf("orderid: %04d, stockid:%04d, price: %6.1f, quantity: %4d, b/s: %c\n", pt->orderid, pt->stockid, pt->price, pt->quantity, pt->bs == 1 ? 'b' : 's');
pt = pt->next;
}
}
/**
* @brief 删除订单
* @param p 订单指针
*
* @return 无
*/
void delOrder(PDATE p)
{
if(p == NULL)
{
printf("not found\n");
}
else
{
printf("deleted order:orderid: %04d, stockid:%04d, price: %6.1f, quantity: %4d, b/s: %c\n", p->orderid, p->stockid, p->price, p->quantity, (p->bs == 1) ? 'b' : 's');
del(p);
}
}
int main()
{
char choice = '\n';
char buyOrSell;
int i;
PSTOCK p0t;
DATE temp;
count = 1;
for(i = 0;i < MAX_DATE_NUM;i++)
adress[i] = NULL;
for(i = 0; i < MAX_STOCK_NUM; i++)
pStockArr[i] = NULL;
home = setnewstock(0);
while(choice)
{
switch (choice)
{
case '1':
{
scanf("%d%f%d %c", &temp.stockid, &temp.price, &temp.quantity, &buyOrSell);
temp.bs = (buyOrSell == 'b'||buyOrSell == 'B'? 1 : 2);
p0t = insert(home, temp.stockid, temp.price, temp.bs, temp.quantity);
marriedDeal(p0t, temp.bs, temp.quantity);
break;
}
case '2':
{
scanf("%d", &temp.stockid);
p0t = pStockArr[temp.stockid];
if(p0t == NULL)
{
printf("buy orders:\n");
printf("sell orders:\n");
goto x;
}
listOrders(p0t);
break;
}
case '3':
{
int tempid;
scanf("%d", &tempid);
delOrder(adress[tempid]);
break;
}
case '0':
{
return 0;
}
}
x:
choice = getchar();
}
}
原文:https://download.csdn.net/download/u013057555/6665043
《交易撮合系统···实现得比较简陋》https://blog.csdn.net/weixin_43296470/article/details/89167379
撮合交易考题:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #任务1:# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
任务是实现一个订单簿。交易所匹配引擎使用一个订单簿来匹配来自买家和卖家的订单。
这是一种简单的机制,使用小示例就可以很好地描述它。
让我们考虑一些假想公司的订单流,这些公司用符号XYZ交易。最初,订单本没有订单:
= = = = = = = = = = = = = = = = =
卖家(问)
------------
买家(投标)
= = = = = = = = = = = = = = = = =
假设某个(匿名)市场参与者以110美元的价格发出了5股的卖出指令。
那么订单将会是这样的:
= = = = = = = = = = = = = = = = =
问
110: 5
------------
报价
= = = = = = = = = = = = = = = = =
片刻之后,其他市场参与者以90美元的价格购买了10股股票:
= = = = = = = = = = = = = = = = =
问
110: 5
------------
90: 10
报价
= = = = = = = = = = = = = = = = =
到目前为止,我们没有任何交易,因为卖方(best ASK)的最低价格是110美元和
买家出价最高(最佳出价)为90美元。
换句话说,目前买家和卖家之间没有匹配。
最佳出价和最佳出价之间的差异称为价差,在这种情况下等于20美元。
几分钟后,一个新的售卖oder以110美元卖10股:
= = = = = = = = = = = = = = = = =
问
110: 5 10
------------
90: 10
报价
= = = = = = = = = = = = = = = = =
110美元卖10股的订单已添加到订单队列的末尾。
这意味着在匹配的情况下,先添加的(5股)将先进行匹配。
几分钟后买家和卖家的更多订单被添加到我们的订单簿中,但目前还没有交易发生。
= = = = = = = = = = = = = = = = =
问
110: 5 10
105: 3 7
------------
100: 4 6
90: 10 2 3
报价
= = = = = = = = = = = = = = = = =
现在,让我们假设一些买家下了一个“激进的”订单:以105美元的价格购买4股。
这将是一个与卖方的最佳价格(即最低价格105美元)相匹配的订单。
在卖方列表:以(105美元的出3股)的订单,比以(105美元,7股)的订单早加入,因此,卖方的3股订单将首先匹配。
因此,我们将看到交易:
3股XYZ以105美元的价格售出
订单会是这样的:
= = = = = = = = = = = = = = = = =
ASK
110: 5 10
105: 3 7
------------
100: 4 6
90: 10 2 3
报价
= = = = = = = = = = = = = = = = =
买了3股,还剩1股没买到,因此剩下去的1股第二次匹配交易:
(105,7股)中的1股XYZ匹配售出
现在订单看起来是这样的:
= = = = = = = = = = = = = = = = =
问
110: 10
105: 6 (7-1 =6)
------------
100: 4 6
90: 10 2 3
报价
= = = = = = = = = = = = = = = = =
换句话说,来自“激进”买家的订单越过了(单个卖家的)账面,产生了两笔交易。
再来一例,现在让我们想象另一个“激进”的卖家想卖(80美元,23股)股票。
换句话说,他或她想卖23股不低于80美元。
第一次交易匹配的是(100,4股)的4股,剩下(100,6股)---因为在以(100,6股)在(100,4股)之后添加的。
订单将是这样的:
= = = = = = = = = = = = = = = = =
问
110: 10
105: 6
------------
100: 4 6
90: 10 2 3
报价
= = = = = = = = = = = = = = = = =
第二次交易为6股,每股100美元:
= = = = = = = = = = = = = = = = =
问
110: 10
105: 6
------------
100: 4 6
90: 10 2 3
报价
= = = = = = = = = = = = = = = = =
第三次交易为10股,每股90美元:
= = = = = = = = = = = = = = = = =
问
110: 10
105: 6
------------
90:10 2 3
报价
= = = = = = = = = = = = = = = = =
第四笔交易为2股,价格为90美元:
= = = = = = = = = = = = = = = = =
问
110: 10
105: 6
------------
90:10 2 3
报价
= = = = = = = = = = = = = = = = =
最后一次交易为1股,价格为90美元(部分匹配或部分执行):
= = = = = = = = = = = = = = = = =
问
110: 10
105: 6
------------
90: 2
报价
= = = = = = = = = = = = = = = = =
现在假设我们有一个新的购买订单,8股,价格为107美元。
我们将看到贸易:
那6股XYZ以105美元的价格的股票先售出:
= = = = = = = = = = = = = = = = =
问
110: 10
------------
90: 2
报价
= = = = = = = = = = = = = = = = =
我们还有2股107美元的价格购买意愿的出价,
但目前低的卖方价格是110美元,所以没有成交,添加到购买意愿队列中:
订单会是这样的:
= = = = = = = = = = = = = = = = =
问
110: 10
------------
107: 2
90: 2
报价
= = = = = = = = = = = = = = = = =
正如您可能注意到的那样,第一个优先级是价格,第二个优先级是在某个价格水平下下单的时间。
它叫做限价订货单。
通常在交易界面中,你可能只会看到每个价格水平上所有订单的总和
只有几个价格水平在最佳买入价/卖出价附近。
如果交易员想从市场上撤回他或她的指令,也有删除指令
(显然每个订单都有唯一的订单id)。
由于显而易见的原因,如果交易员先删除订单,然后再添加订单,新的订单将被添加到queue的末尾)
你的实现应该读取市场数据文件并构建订单簿,
将已发生的交易和订单的最终状态打印到标准输出。
市场数据文件格式:
每一行代表按时间顺序添加的顺序。
每行的第一个字节表示消息类型:
“A”——新秩序
' X ' -删除顺序
订单的格式为一行的其余部分:order_id,边,数量,价格
例如:
16113575, B, 18,585
它解码:
A =添加新订单
16113575 =订单id
订购单
18 =要买的股票数目
585 =价格
输入文件示例:
A,100000,S,1,1075
A,100001,B,9,1000
A,100002,B,30,975
A,100003,S,10,1050
A,100004,B,10,950
A,100005,S,2,1025
A,100006,B,1,1000
X,100004,B,10,950
A,100007,S,5,1025
A,100008,B,3,1050
X,100008,B,3,1050
X,100005,S,2,1025
额外加分:可测试性和性能说明。