【交易】撮合交易

试利用单链表作为存放委托的数据结构(撮合队列),编写一模拟股票交易的程序,该程序有以下几个功能:

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

额外加分:可测试性和性能说明。

posted on 2022-10-04 01:25  bdy  阅读(34)  评论(0编辑  收藏  举报

导航