专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

基于Python3双队列数据结构搭建股票外汇交易匹配撮合系统

  如果你爱他,那么送他去股市,因为那里是天堂;如果你恨他,送他去股市,因为那里是地狱。
  在过去的一年里,新冠疫情持续冲击世界经济,全球主要股票市场的波动都相对频繁,尤其是A股,正所谓:曾经跌停难为鬼,除非解套才做人;抄底时难抛亦难,反弹无力百花残。对于波谲云诡的股票市场,新投资人还是需要谨慎入场,本次我们来利用双队列的数据结构实现实时在线交易匹配引擎,探索股票交易的奥秘。
  首先需要明确一点,证券交易和传统的B2C电商系统交易完全不同,证券交易系统提供的买卖标的物是标准的数字化资产,如美元、股票、比特币等等,它们的特点是数字计价,可分割买卖,也就是说,当我们发起买盘申请的时候,需要有价格对应的卖盘响应,才能真正完成交易,反之亦然。
  具体逻辑是:所有买盘或者卖盘的订单队列都传递给匹配引擎,匹配引擎尝试将它们的价格进行匹配。该匹配队列分为买单(按价格升序排列,出价最高的优先交易)和卖单(按降序排列,卖价最低的优先交易)。如果股票订单找不到与匹配的价格,那么该订单就继续保存在订单队列中的原适当位置。
  这里我们以实际的案例来看一下相关匹配算法的实现,假设我有两个订单队列,一个买盘,一个卖盘:买盘价格数量1005010010905883卖盘价格数量1705018040199102005
  最常见的匹配算法就是价格时间优先队列。订单主要根据价格进行匹配,如果以相同的价格水平存在多个订单,则最早的订单将首先被匹配,这也和队列原理相同:先入先出。
  如上所示,假设有两个订单紧挨着。第一个是以100块钱的价格买入50股的买入订单,第二个也是以相同价格买入10股的买入订单。鉴于订单与任何卖价都不匹配(由于其价格低于最低的卖价),所以它们都被放置在订单队列中。第一订单和第二订单以相同的价格水平存储,但是由于时间优先,前者比后者具有优先权。这基本上意味着,第一个订单将被放置在买入队列中的第二个订单的前面。
  而卖盘同理,首先卖价最低的优先交易,如果卖价相同,则时间优先,先进队列的先交易,可是很多散户都遇见过一种情况,就是如果手里的一支股票连续跌停,就算拼命挂低价单也很难卖出去,甚至可能直接跌到退市血本无归,这是为什么呢?
  因为当一只股票跌停时,也意味着有一大堆筹码堆积在跌停板上,想卖出去是不容易的,得排队,理论上按照时间优先、价格优先的交易原则排队成交,但跌停的情况下,只存在时间优先的考虑,也就是说,如果想在封死跌停板时把股票卖出去,就得尽早对该股票挂跌停板价格卖出。
  可实际上,一只股票跌停,不光是小部分散户卖不出去,而是大多数散户都卖不出去,都在恐慌性出货,大家都在排队卖。更何况,股票买卖是通过券商进行的,而券商有VIP快速通道也不是什么秘密,一些大资金的大户、游资、机构享有券商优待,或通过租用通道实现对盘面的快速优先买卖,这也导致了在股票涨停板抢筹、跌停板出货时存在一定的不公平性,也就说,交易队列并非完全遵照价格时间定序,还有可能出现优先级(加权)队列,所以,跌停时跑不了,涨停时买不进就不是什么新鲜事了。
  另外,还需要注意匹配算法中的价格一直而数量匹配填充的问题,假设买单10块挂单50手,卖单10块挂单30手,则匹配的价格为10块钱,在买一卖一各显示30手,买单队列首位置就会有20手在排队,如下所示:买盘价格数量1050卖盘价格数量10301150
  经过匹配算法之后:买盘价格数量1020卖盘价格数量1150
  OK,了解了基本概念,让我们用Python3具体实现,首先需要定义两个类,订单和交易,订单对象作为匹配算法之前的元素,而交易对象则是匹配之后的成交对象:classOrder:definit(self,ordertype,side,price,quantity):self。typeordertypeself。sideside。lower()self。pricepriceself。quantityquantityclassTrade:definit(self,price,quantity):self。pricepriceself。quantityquantity
  这里type是订单类型,side代表买单或者卖单,price为价格,quantity为数量。
  紧接着我们来实现订单队列:classOrderBook:definit(self,bids〔〕,asks〔〕):self。bidssorted(bids,keylambdaorder:order。price)self。askssorted(asks,keylambdaorder:order。price)deflen(self):returnlen(self。bids)len(self。asks)defadd(self,order):iforder。typebuy:self。bids。append(order)eliforder。typesell:self。asks。append(order)defremove(self,order):iforder。typebuy:self。bids。remove(order)eliforder。typesell:self。asks。remove(order)
  这里的订单队列很容易地实现为具有两个排序列表的数据结构,其中两个列表包含两个按价格排序的订单实例。一种按升序排序(买单),另一种按降序排序(卖单)。
  下面来实现系统的核心功能,匹配引擎:fromcollectionsimportdequeclassMatchingEngine:definit(self):self。queuedeque()self。orderbookOrderBook()self。tradesdeque()
  首先,我们需要两个FIFO队列;一个用于存储所有传入的订单,另一个用于存储经过匹配后所有产生的交易。我们还需要存储所有没有匹配的订单。
  之后,通过调用。process(order)函数将订单传递给匹配引擎。然后将匹配生成的交易存储在队列中,然后可以依次检索(通过匹配引擎交易队列),也可以通过调用。gettrades()函数将其存储在列表中。defprocess(self,order):self。match(order)defgettrades(self):tradeslist(self。trades)returntrades
  随后就是匹配方法:defmatch(self,order):iforder。sidebuy:filled0consumedasks〔〕foriinrange(len(self。orderbook。asks)):askself。orderbook。asks〔i〕ifask。priceorder。price:break卖价过高eliffilledorder。quantity:break已经匹配iffilledask。quantityorder。quantity:filledask。quantitytradeTrade(ask。price,ask。quantity)self。trades。append(trade)consumedasks。append(ask)eliffilledask。quantityorder。quantity:volumeorder。quantityfilledfilledvolumetradeTrade(ask。price,volume)self。trades。append(trade)ask。quantityvolume没匹配成功的iffilledorder。quantity:self。orderbook。add(Order(limit,buy,order。price,order。quantityfilled))成功匹配的移出订单队列foraskinconsumedasks:self。orderbook。remove(ask)eliforder。sidesell:filled0consumedbids〔〕foriinrange(len(self。orderbook。bids)):bidself。orderbook。bids〔i〕ifbid。priceorder。price:breakiffilledorder。quantity:breakiffilledbid。quantityorder。quantity:filledbid。quantitytradeTrade(bid。price,bid。quantity)self。trades。append(trade)consumedbids。append(bid)eliffilledbid。quantityorder。quantity:volumeorder。quantityfilledfilledvolumetradeTrade(bid。price,volume)self。trades。append(trade)bid。quantityvolumeiffilledorder。quantity:self。orderbook。add(Order(limit,sell,order。price,order。quantityfilled))forbidinconsumedbids:self。orderbook。remove(bid)else:self。orderbook。add(order)
  逻辑上并不复杂,基本上就是在订单队列中遍历,直到收到的订单被完全匹配为止。对于每个匹配成功的订单,都会创建一个交易对象并将其添加到交易队列中。如果匹配引擎无法完全完成匹配,则它将剩余量作为单独的订单再添加会订单队列中。
  当然了,为了应对高并发场景,实现每秒成千上万的交易量,我们可以对匹配引擎进行改造,让它具备多任务异步执行的功能:fromthreadingimportThreadfromcollectionsimportdequeclassMatchingEngine:definit(self,threadedFalse):self。queuedeque()self。orderbookOrderBook()self。tradesdeque()self。threadedthreadedifself。threaded:self。threadThread(targetself。run)self。thread。start()
  改造线程方法:defprocess(self,order):ifself。threaded:self。queue。append(order)else:self。match(order)
  最后,为了让匹配引擎能够以线程的方式进行循环匹配,添加启动入口:defrun(self):whileTrue:iflen(self。queue)0:orderself。queue。popleft()self。match(order)print(self。gettrades())print(len(self。orderbook))
  大功告成,完整代码如下:classOrder:definit(self,ordertype,side,price,quantity):self。typeordertypeself。sideside。lower()self。pricepriceself。quantityquantityclassTrade:definit(self,price,quantity):self。pricepriceself。quantityquantityclassOrderBook:definit(self,bids〔〕,asks〔〕):self。bidssorted(bids,keylambdaorder:order。price)self。askssorted(asks,keylambdaorder:order。price)deflen(self):returnlen(self。bids)len(self。asks)defadd(self,order):iforder。typebuy:self。bids。append(order)eliforder。typesell:self。asks。append(order)defremove(self,order):iforder。typebuy:self。bids。remove(order)eliforder。typesell:self。asks。remove(order)fromthreadingimportThreadfromcollectionsimportdequeclassMatchingEngine:definit(self,threadedFalse):order1Order(ordertypebuy,sidebuy,price10,quantity10)order2Order(ordertypesell,sidesell,price10,quantity20)self。queuedeque()self。orderbookOrderBook()self。orderbook。add(order1)self。orderbook。add(order2)self。queue。append(order1)self。queue。append(order2)self。tradesdeque()self。threadedthreadedifself。threaded:self。threadThread(targetself。run)self。thread。start()defrun(self):whileTrue:iflen(self。queue)0:orderself。queue。popleft()self。match(order)print(self。gettrades())print(len(self。orderbook))defprocess(self,order):ifself。threaded:self。queue。append(order)else:self。match(order)defgettrades(self):tradeslist(self。trades)returntradesdefmatch(self,order):iforder。sidebuy:filled0consumedasks〔〕foriinrange(len(self。orderbook。asks)):askself。orderbook。asks〔i〕ifask。priceorder。price:break卖价过高eliffilledorder。quantity:break已经匹配iffilledask。quantityorder。quantity:filledask。quantitytradeTrade(ask。price,ask。quantity)self。trades。append(trade)consumedasks。append(ask)eliffilledask。quantityorder。quantity:volumeorder。quantityfilledfilledvolumetradeTrade(ask。price,volume)self。trades。append(trade)ask。quantityvolume没匹配成功的iffilledorder。quantity:self。orderbook。add(Order(limit,buy,order。price,order。quantityfilled))成功匹配的移出订单队列foraskinconsumedasks:self。orderbook。remove(ask)eliforder。sidesell:filled0consumedbids〔〕foriinrange(len(self。orderbook。bids)):bidself。orderbook。bids〔i〕ifbid。priceorder。price:breakiffilledorder。quantity:breakiffilledbid。quantityorder。quantity:filledbid。quantitytradeTrade(bid。price,bid。quantity)self。trades。append(trade)consumedbids。append(bid)eliffilledbid。quantityorder。quantity:volumeorder。quantityfilledfilledvolumetradeTrade(bid。price,volume)self。trades。append(trade)bid。quantityvolumeiffilledorder。quantity:self。orderbook。add(Order(limit,sell,order。price,order。quantityfilled))forbidinconsumedbids:self。orderbook。remove(bid)else:self。orderbook。add(order)
  测试一下:meMatchingEngine(threadedTrue)me。run()
  返回结果:liuyue:mytornadoliuyuepython3Usersliuyuewodfanworkmytornadotestordermatch。py〔main。Tradeobjectat0x102c71750〕2〔main。Tradeobjectat0x102c71750,main。Tradeobjectat0x102c71790〕1
  没有问题。
  结语:所谓天下熙熙,皆为利来;天下攘攘,皆为利往。太史公这句名言揭示了股票市场的本质,人性的本能就是追求利益,追求利益却要在决对原则之下,但是资本市场往往是残酷的,王霸雄图,荣华敝屣,到最后,也不过是尽归尘土。

国庆节假期来临,往年火爆三个大省旅游区今年被大众游客冷落了2022年国庆节来了,大家已经有按捺不住心情在路上了,2022年10月1日零时起,高速公路免费七天,根据铁路部门消息今年国庆节旅客出行人次6850万长途旅客,这是五年来最低数据,那李白与安徽众鸟高飞尽,孤云独去闲李白与安徽缘分深厚,准确地说,李白与皖南缘分很深。这不仅是游山玩水,更是生死相托,李白最终是在安徽当涂仙逝。李白来过芜湖,望天门山长江天门中断楚江开,碧水东流至此回。两岸青山相对出隐藏安徽大山中隐居,已传67世的匈奴后裔,至今机关仍无人破解旅游对于时下的很多有钱有闲的国人来说,其实也是一个各花入各眼的行为和选择,有人喜欢奇险风光,有人喜欢海阳光海滩,有人喜欢结合历史文化探寻历史的痕迹。对于这类的游客来说,安徽大山里有我们的节日国庆假期去哪儿玩?重庆两江国际影视城百余场街区演出轮番上演封面新闻记者李茂佳9月30日,封面新闻从重庆两江新区获悉,国庆假期,两江国际影视城将推出金秋花灯节街区大巡演国潮奇妙夜等丰富多彩的主题活动,每日有上百场街区演出轮番上演。景区内部。安徽宁国山乡晒秋忙9月29日拍摄的安徽省宁国市南极乡龙川村。近日,一场热闹喜庆的秋收嘉年华系列活动在安徽省宁国市南极乡龙川村举行,游客们现场体验山核桃采摘山核桃制作和品鉴高山露营等活动。宁国市南极乡安徽宁国山乡晒秋忙9月29日拍摄的安徽省宁国市南极乡龙川村。近日,一场热闹喜庆的秋收嘉年华系列活动在安徽省宁国市南极乡龙川村举行,游客们现场体验山核桃采摘山核桃制作和品鉴高山露营等活动。宁国市南极乡单车上的幸福文卜娣娣秋日的傍晚,我喜欢下班后骑一辆单车,心无旁骛的在马路上游荡。脚慢慢踩起踏板,追逐着天边的夕阳,感觉有风在发间穿过,在裙角穿过,碎金一样的光斑透过树荫落下来,在脸颊上奔跑着,九月再见十月你好的文案说说1九月再见,十月你好!新的征程已经开始。愿你在金秋十月,收获不一样的自己。世界上所有的惊喜和好运,都是你累积的惊喜和善良。做一个温柔纯良,内心强大的人。温暖自己,照亮别人。十月,继刘鑫只是个柔弱女,不是神1有人责怪刘鑫无能。我觉得,我们在这件事上所做的一切是为了我们自己,为了我们自己生存的这个社会的公平正义。我们不应该把自己的无能转嫁到刘鑫身上,想让她承担我们的无能,这对她的伤害不我的认知最感兴趣的人我最感兴趣的历史人物我存于世对所知所遇所识之人都感兴趣,我感谢上苍也就是我父母给了我生命,來到这个美好神奇又充滿了诱惑的世界,但它确让我经历了探知求索向往只至明致意义地过程。并于愚原来你是这样的重庆人来源央视新闻这次山火,让我重新认识了重庆人01hr原来你是这样的重庆人,看上去悠哉游哉插科打诨,但骨子里是袍哥性格,江湖侠义。火,再无情再凶险,你义无反顾地扑到前面,不是孤零的一个
龙凤双胞胎马上一岁了,母乳还够吃,我是继续哺乳还是给孩子戒奶?我在学习育婴师的时候老师就跟我说过,母乳的孩子长到6个月了就应该给他加辅食了。你自己有母乳也要给孩子加辅食,孩子越大你的母乳营养成份越低,你已经满足不了孩子日常所需要的各种维生素。不到2分钟3次犯规!范子铭李慕豪包夹易建联,他们成功了吗?昨天首钢队的防守还算成功的,仅让宏远得到了92分,但首钢自己的进攻更加惨不忍睹,除了范子铭拿下22分以外,其他点均被宏远成功扼制住了,输在进攻乏力上了,好不容易请来的林大侠为什么不男性怎么喝酒有益于健康?喝酒是目前社交一个不可避免的方法,中国人不喝酒是不可能的。还有一个多月就春节了,每年春节,酒驾的人很多,醉酒住院的很多,但中国人就这样,遇到节日,没有酒是万万不可能的,但喝酒一定要中超联赛各家俱乐部老板都是做什么买卖的?谁最有钱?作为中国体育圈最烧钱的游戏,想玩好一支足球队那背后绝对需要巨额的真金白银来做支撑。单以中超近些年的经营情况来看,一年丢进去几个小目标是再正常不过的事情。如果放眼世界足坛,五大联赛部DNF强化11的魔法石,和增幅8的魔法石,差距有多大,需要换吗?谢谢邀请!DNF桂月好礼缤纷活动,全勤玩家本周就可以获得红字书2本和代币券2万的奖励了,勇士们是普天同庆啊,但同时,有玩家也产生了疑惑现在是强化11的魔法石,可以打红字增幅到8,强和平精英正面对枪总是自己先倒地,是不是不适合玩这游戏?有什么能够快速提升的办法?大家好,恰巧最近有玩家和游戏谈起正面刚枪这个问题,心情比较低沉的对游戏君说他已经是吃鸡9个赛季的老玩家了,但是从最开始玩这个游戏一直到现在,几千场的游戏似乎对他的技术方面并没有太大中国申办世界杯足球赛的可能性大吗?不请自来。中国申办男足世界杯最大的障碍来自什么?是中国男足国家队的水平问题。其实从国际足联亚足联乃至全世界,都在期待中国能办世界杯,不管是外界环境还是内部条件,早就已经成熟了。从国樊振东若在世乒赛夺冠的话,问题是刘国梁能安心让马龙退役吗?樊振东在世乒赛上能否夺得男单冠军跟马龙能否退役没大关系。马龙退不退役取决于他本身的状况,如果身体允许他可能还要再打几年,如果身体出了问题不适合再打下去,恐怕随时都可能退役。对于刘国助听器戴时间长了,有伤害吗?如果佩戴合适的助听器并不会使听力损失造成恶化,相反,它不仅可以帮助我们听到声音,使生活更加便利,还会对听觉中枢保持持续的听觉刺激。耳朵和大脑一样,都是用进废退。发现戴助听器后听力下油性皮肤怎么办?油性皮肤怎么办?油性皮肤可以进行皮肤护理,减少出油如果出油严重,可以到皮肤科或医学美容科就医咨询。皮肤护理的主要措施有清洁皮肤脂质补水保湿选择合适的洗面奶和收缩水等。清洁皮肤油性皮央企外迁,北京打造科创中心,哪些区域将搭上发展快车?我觉得北京打造科创中心昌平搭上发展快车希望最大!地域广阔!交通方便!科技人员集中!天时地利人和!条条具备!央企外迁,北京打造科创中心和国际消费城市,这是一个大动作,肯定会带动一些区
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网