股票交易系统

效果展示,如下动图:

首先简述一下股票交易规则:

  • 买卖股票,股民可以自行选择股票的买入或卖出价格和股票的数量,但是用户不一定马上就交易成功,只有当股票价格低于买入价才有机会买入,高于卖出价才有机会卖出。所以需要做委托处理。所以我们通常说的是委托下单,而不是说下单。
  • 股票买卖以100股为单位,100股也称为1手。
  • 同一股票可以多次买入,可以多次卖出,但是卖出的总股数不能高于买入的总股数,并且需要在资金的支持下才能进行。
  • 在交易时间的时候,股票的价格是随时波动的
  • 等待交易的卖家的委托价格都要比现价高,等待交易的买家的委托价格都要比现价低,
  • 红色(涨):当股票价格比前一交易日的收盘价高时,通常用红色来表示涨幅。
  • 绿色(跌):当股票价格比前一交易日的收盘价低时,通常用绿色来表示跌幅。
  • 细节:如果股票原来为红色,股票下跌却又没有接到前一天的收盘价低的时候,会变为绿色,然后又转变为红色。绿股同理。
  •  然后还有总资产与可用资产的区别,总资产不一定都可用。
  • 可用资产:可用资产是总资产减去委托买入所损耗的金额,无论交易成功与否
  • 总资产:   总资产是在交易成功之后,各股的涨幅买入金额的上可用资产的值
  • 仓位:指的是的支出资金占总资金的百分比,并且指的是交易成功之后的支出资金,而不是委托状态的支出资金。
  • 盈率:盈率=(成本价-现价)/成本价*100% 只有在交易成功后才涉及到,并且会随着现价的波动而波动。
  • 总盈率:用户买入股票后单股的盈率之和。
  • 系统功能:

        1.程序启动后给用户提供100w的资金,进行模拟炒股

        2.用户可以通过输入股票代码查看股票详细信息

        3.用户可以对股票进行买进,卖出

        4.查看委托状态操作

        5.查看仓库状态操作

        6.用户可以对自选股进行增删查

        7.用户可以通过键盘上的上下键来控制“→”选择操作,回车键确认

        8.用户可以对股票进行排序,通过键盘上的上下键来控制“↓ ↓”选择需要排序的数据,提供现价和涨幅的排序,回撤一次,股票进行降序排序,再次回撤进行升序排序,循环往复直到把箭头移走。

设计概要:

1.窗口以及光标设置

        1.1.设计合适的窗口大小

        1.2.设置窗口名称

        1.3.封装光标隐藏函数和光标显示函数

        1.4.封装光标坐标设置函数--SetPos

2.股票信息获取 

        因为股票信息量一些大,所以我们可以通过先把它写到文件里然后从文件里读取,该片文章的股票信息参考是6月9日的股票市场。

3.交易页面设计

        我们可以做一个小区间内的随机数让股票价格在一个小范围内波动,该系统比较简洁,就不去考虑股票前一天的收盘价了,我们直接以现价与开盘价做比较,现价高于开盘价就呈现红色,反之为绿色。并且提供菜单。

4.主逻辑

        设计两条线程,一条做股票的界面展示,一条做背后的主逻辑,我在在这简称为打印线和逻辑线,逻辑线接收用户的信息并做处理,并反馈给打印线(通过共用资源)。两个线程互相配合完成工作。

5.头文件的声明

        5.1.股票信息:使用用一个结构体来维护,成员包括,股票名称,股票代码,开盘价,现价,涨幅等等。

        5.2.委托状态:设计到状态的处理,使用枚举类型更为适应,成员包括,未委托,委托待买入,委托待卖出,买入交易成功,卖出交易成功。

        5.3.持股信息:持股信息使用结构体来维护更为适应,并且成员需要有股票信息,然后做成链表。

        5.4.仓库信息: 使用结构体维护成员包括:总资产,可用资产,总盈率,仓位和持股信息

        5.6头文件的部分声明:

编译环境的配置 

一、手搓股票信息

        股票信息量比较大,考虑把它放到文件里,然后运行程序的时候再从仓库里取,如下:

        每一支股票的信息我们用一个结构体类型来储存,然后再把所有股票放在一个结构体数组里面,因为涉及到股票信息在整个工程中会被频繁使用,所以把它做成全局变量,数组成员个数size随时会改变,所以用一个#define在头文件定义。要注意以下一点:

 向文件里读取信息:

	FILE* pf = fopen("stcok.txt", "r");if (!pf){perror("fopen");return 1;}for (int i = 0; i < size; i++){fscanf(pf, "%s %s %f %f %f %f %f %f %f %f %f %f",arr[i].name, arr[i].code, &arr[i].price, &arr[i].begin,&arr[i].max, &arr[i].min, &arr[i].amount, &arr[i].rate,&arr[i].sumh, &arr[i].money, &arr[i].value, &arr[i].ratio);}

二、交易页面设计

1.函数封装 

 color函数,SetPos函数,FCursor函数,OCursor函数的封装:

void FCursor()//关闭光标
{HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO Info;GetConsoleCursorInfo(houtput, &Info);Info.bVisible = false;SetConsoleCursorInfo(houtput, &Info);
}
void OCursor()//显示光标
{HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO Info;GetConsoleCursorInfo(houtput, &Info);Info.bVisible = true;SetConsoleCursorInfo(houtput, &Info);
}
void color(int x)//设置控制台颜色
{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);
}
void SetPos(int x, int y)//设置光标的坐标
{HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//GetStdHandle获取柄,HANDLE接收柄COORD pos = { x,y };//坐标SetConsoleCursorPosition(houtput, pos);
}

2.线程创建:

	//将仓库信息和持股信息封装送入线程中HoldStock* head = NULL;Warehouse wh = { 1000000,1000000,0,100.00,NULL };HW pw;pw.r = 1, pw.hs = &head, pw.ws = &wh;HANDLE thp1 = NULL, thp2 = NULL;// 初始化临界区InitializeCriticalSection(&cs);// 创建线程thp1 = CreateThread(NULL, 0, Print,(LPVOID)&pw, 0, NULL);//这里不能把pw直接传过去!!thp2 = CreateThread(NULL, 0, Run, (LPVOID)&pw, 0, NULL);//if (!thp1 || !thp2){exit(-1);}// 等待线程结束WaitForSingleObject(thp1, INFINITE);WaitForSingleObject(thp2, INFINITE);// 销毁临界区DeleteCriticalSection(&cs);// 关闭线程句柄CloseHandle(thp1);CloseHandle(thp2);

        接下来进入打印线,进入打印线后先给数据解封装,因为考虑到股票信息会在整个工程中打印输出,所有先直接做一个死循环,并且在开头和结尾上锁和解锁。其他问题先不考虑。

        在输出前先要设置光标位置,以便信息在准确的位置输出,SetPos用来设置光标信息,color用来设置控制台颜色。

2.价格波动模拟 

        这个当然需要使用随机数来获取,举一个例子如下,这只是个例子还可以用其它方法来模拟。

		srand((unsigned int)time(NULL));for (int i = 0; i < size; i++){int u = rand() % 5;switch (u){case 0:break;case 1:arr[i].price += 0.01;break;case 2:arr[i].price += 0.1;break;case 3:arr[i].price -= 0.01;break;case 4:arr[i].price -= 0.1;break;}arr[i].amount = (arr[i].price - arr[i].begin) / arr[i].begin * 100;if (arr[i].price > arr[i].max)arr[i].max = arr[i].price;if (arr[i].price < arr[i].min)arr[i].min = arr[i].price;}

 

其它信息的输出和这个类似,这里就不再展示。 

三、菜单设计--menu()

  • 买入 
  • 卖出 
  • 查看股票  
  • 添加自选股 
  • 删除自选股
  • 查看自选股
  • 查看委托
  • 查看仓库

        菜单,给用户提供8个操作,得用户选定后用switch语句进行分开处理,其中自选股的添加删除查找操作比较简单,就是链表的增删查,对这三个点就不再过多叙述。查看股票的话我们可以通过用户输入个证劵代码去查找对应股票的数组下标,然后利用双线程资源共享的特点把输出下标进行更改。接下来看主要来分析一下其它操作。

        当然除此之外还有排序功能,这个可以用qsort函数去处理,这样比较高效。

四、链表设计及更新--List

        为了方便,考虑创建一个链表来做数据的储存,对于自选股的增删查使用链表再合适不过了,而这个我们可以把自选股和交易股做成同一支链表

        有的人可能会想,自选股也可能是交易股啊!对,不过没关系。添加自选股的时候我们进行插入节点。进行委托下单的时候也插入节点。而委托状态就可以区分他们。自选股的委托状态一定是未委托,而交易股委托状态一定不是未委托。

        链表的更新,因为链表里储存的是交易股和自选择股,股票的价格涨幅等等都会随时变化,所以需要随时的更新,因为股票信息的数组是全局变量,只需要封装一个函数把对应的股票赋上新的值。

五、买入处理--Buy()

在买入处理函数中需要做的事如下:

  • 判断股票是否存在。
  • 判断可用金额是否充足
  • 判断是否是以100股为单位买入

如果用户输入不符合交易规则,要做相应的提示输出。并且需要用户重新输入

符合交易规则后的处理:

  • 将委托状态置为委托待买入。
  • 将买入价存储到持股信息中。
  • 将买入股数储到持股信息中。
  • 可用资金减掉本次交易的资金量。

最后反馈给客户委托成功。

六、卖出处理--Sell()

在买入处理函数中需要做的事如下:

  • 判断该支股票是否被买入(委托状态是否为成功买入)。
  • 判断持有股数是否充足
  • 判断是否是以100股为单位卖出

如果用户输入不符合交易规则,要做相应的提示输出。并且需要用户重新输入

符合交易规则后的处理:

  • 将委托状态置为委托待卖出。
  • 将卖出价存储到持股信息中。
  • 将卖出股数储到持股信息中。

最后反馈给客户委托成功。

七、处理委托--EnDealt()

        处理买入:如果现价比卖入价低,交易成功

        处理卖出:如果卖出价比现价高,交易成功,成功卖出后可用资产需要增加,并且记录盈率,因为卖出股票后它的盈率就不随现价的波动而波动,可能会丢失导致后面的总资产无法准确计算,所以需要记录。

代码如下:

void EnDealt(HoldStock* ch,Warehouse* cw)//处理委托
{//不用保存ch的初始值,因为它只是临时变量while (ch){if (ch->en == BuyWait && ch->stk.price < ch->cost)//现价比卖入价低,交易成功ch->en = BuyOK;if (ch->en == SellWait && ch->stk.price <ch->out)// 现价比卖出价高,交易成功{ch->pf = (ch->out-ch->cost) / ch->cost * 100;//计算盈率cw->own += ch->pf / 100 * ch->cost * ch->sm;//计算可用资产ch->en = SellOK;//交易成功}ch = ch->next;}	
}

委托展示--EnShow()

        在写这个函数要注意一个细节,先需要思考一下需要展示的是哪些股票信息?只要不是未委托的股票都需要展示,而委托卖出,和卖出成功的股票是需要打印两次的,因为委托卖出和卖出成功的股票一定是买入成功的,也需要打印,而委托状态只能储存一个状态。而这个问题可以用一个新加一个un变量来解决。

void EnShow(HoldStock* head)//展示委托//!!
{SetPos(38, 22);printf(" 代码    名称    现价   涨幅");int i = 1, un = 1;while (head){if (head->en != NO){SetPos(38, 22 + i);printf("%s %s", head->stk.code, head->stk.name);head->stk.amount > 0 ? color(116) : color(114); printf("%7.2f  %.2f%% ", head->stk.price, head->stk.amount); color(112);if (un==1){SetPos(69, 22 + i); printf("买:%.2f", head->cost);}else{SetPos(69, 22 + i); printf("卖:%.2f", head->out);}SetPos(78, 22 + i);if (un == 1){if (head->en == BuyWait){color(121); printf("待买入   ");}elsecolor(124); printf("交易成功");SetPos(87, 22 + i); printf("数量:%d股", head->sm); color(112);}else{if (head->en == SellWait){color(121); printf("待卖出   ");}elsecolor(124); printf("交易成功");SetPos(87, 22 + i); printf("数量:%d股", head->sel); color(112);}i++;if (head->en == SellWait || head->en == SellOK)//让要卖出的股票打印两次un = un == 0 ? 1 : 2;}if (un==2)un = 0;elsehead = head->next;}
}

八、更新仓库--WaDealt()

        需要对总资金,总盈率,仓位进行计算。而可用金额已经在买入处理,和委托处理中计算了,在这里不用处理。
        这里为了这方便。不用考虑原资产。原仓位。和总盈率。直接把它们都初始化一次重新开始计算。注意在计算总资产的时候要将卖出的股票的盈利加上

void WaDealt(Warehouse* cw, HoldStock* ch)//仓库调整
{float cv = 1000000.00;//总资产float prosum = 0.0;//总盈率float cu = 0.0;//仓位while (ch){if (ch->en==BuyOK){cv += (ch->stk.price - ch->cost) * ch->sm;prosum += (ch->stk.price - ch->cost)/ch->cost * 100;cu += ch->cost * ch->sm;}if (ch->en == SellOK){cv += ch->pf / 100 * ch->cost * ch->sm;prosum += ch->pf;}ch = ch->next;}cw->coin = cv;cw->profit = prosum;cw->place = cu/10000;
}

仓库展示--WaShow()

        相比委托的展示,仓库的展示还比较简单,不过要注意一点,卖完的股票就不用展示就不用展示。如下:

void WaShow(Warehouse* ck, HoldStock* head)
{color(112); SetPos(34, 22); printf("仓库");SetPos(34, 23); ck->coin >= 1000000 ? color(116) : color(114); printf("总资产:%.2f ", ck->coin); color(112);ck->profit >= 0 ? color(116) : color(114); printf("盈率:%.2f%%  ", ck->profit); color(112); printf("仓位:%.2f%% ", ck->place);printf("可用资产:%.2f  ", ck->own);HoldStock* ph = head;SetPos(34, 25);printf(" 代码     名称     现价 / 成本    涨幅 ");int i = 1;while (ph){if (ph->en == BuyOK|| ph->en == SellWait||(ph->en==SellOK&&ph->sm-ph->sel>=100)){SetPos(34, 25 + i);printf("%s  %s", ph->stk.code, ph->stk.name);ph->stk.amount > 0 ? color(116) : color(114); printf("%8.2f/", ph->stk.price); color(112);printf("%.2f   ", ph->cost);ph->stk.amount >= 0 ? color(116) : color(114); printf("%.2f%%  ", ph->stk.amount); color(112);//SetPos(68, 25 + i);//ph->stk.money > 1000 ? printf("%.2f万", ph->stk.money) : printf("%.2f亿 ", ph->stk.money);ph->cost <= ph->stk.price ? color(116) : color(114); printf("盈率:%.2f%% ", (ph->stk.price - ph->cost) / ph->cost * 100); color(112);color(121); printf("持股:%d ", ph->sm-ph->sel); color(112);i++;}ph = ph->next;}
}

源码:由于源码代码量比较大,就不放在文章中,如果需要请私信我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/354723.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ccie在香港值钱吗?ccie认证很难考吗?

思科ccie认证可以算得上是网络高级工程师的一个标配证书&#xff0c;特别是在香港工作的朋友更是需要尽早拿下这个认证&#xff0c;它能让你的求职之路更为顺利。而已经入职的工程师为了不被时代所淘汰&#xff0c;也需要该证书保驾护航。 你知道ccie在香港值钱吗?ccie认证是不…

redis高可用-哨兵机制

一&#xff1a;背景 上一节我们已经实现了redis的主从同步&#xff0c;从而实现服务的流量分摊和数据高可用&#xff0c;但是出现故障以后&#xff0c;需要人工手动接入&#xff0c;手动切换主从&#xff0c;来实现故障转移。这是比较麻烦的&#xff0c;毕竟人不能实时盯着服务…

Covalent实现对1000亿笔链上交易解析,支持AI长期数据可用性

在区块链与人工智能&#xff08;AI&#xff09;交汇处&#xff0c;讨论往往集中于去中心化推理和去中心化训练等方面。然而&#xff0c;这一数据的关键组成部分却一直未得到足够的重视。一个主要问题是&#xff1a;我们如何保护 AI 模型中的数据不受偏见和操纵的影响&#xff1…

【计算机组成原理】指令系统考研真题详解之拓展操作码!

苏泽 “弃工从研”的路上很孤独&#xff0c;于是我记下了些许笔记相伴&#xff0c;希望能够帮助到大家 另外&#xff0c;利用了工作之余的一点点时间&#xff0c;整理了一套考研408的知识图谱&#xff0c; 我根据这一套知识图谱打造了这样一个408知识图谱问答系统 里面的每一…

C语言的网络编程

目录 引言 一、TCP/IP概述 1. TCP&#xff08;Transmission Control Protocol&#xff09; 2. UDP&#xff08;User Datagram Protocol&#xff09; 二、Socket编程基础 1. 服务器端 2. 客户端 三、URL与HTTP编程 1. 使用libcurl进行HTTP请求 表格总结 TCP/IP与Socke…

镭速传输界面优化之静态文件加载

镭速一直是众多企业传输大文件和大数据的优选对象&#xff0c;速度快、稳定且安全是市场上传输软件脱颖而出的立杆标签&#xff0c;那么同样在界面优化和体验的强大也能够给企业用户带来许多直观的感受&#xff0c;那么今天我们就来谈谈镭速是如何做到这些的&#xff0c;在界面…

【锐捷】VSU环境下部署VAC

配置要求 1.两台核心交换机部署VSU&#xff0c;Domain ID为1&#xff0c;S1的Switch ID为1&#xff0c;优先级为150&#xff0c;设备描述为VSU-S1&#xff1b;S2的Switch ID为2&#xff0c;优先级为120&#xff0c;设备描述为VSU-S2&#xff1b;两台设备的G0/48口用于BFD双机检…

go语言对接S3存储的SDK(支持minio和OSS)

背景 在某个项目中&#xff0c;客户要求支持S3协议的存储&#xff0c;因为之前的项目是go来开发的支持的oss和minio 。 但并不一定支持S3的协议&#xff0c;而且使用了二种SDK&#xff0c;感觉比较麻烦。 既然客户提出来了要求。那我们改一下就是了。 操作 引入 go语言中有对…

中国最全的hive sql 函数集合(持续更新)

#6/20/24 增加greatest函数&#xff1a; select greatest(1,2,3,4,5,2) 结论&#xff1a;可以用hive presto spark得出正确的结果值 #6/20/24 增加last_value(cl1) ignore nulls over(order by ts ) as dt 函数&#xff1a; 有数据集&#xff1a; 1 1 1 2 2   3 3 …

振幅调制与解调电路

本章学习内容与重难点 调制的原因 调制就是把低频信号的信息带到高频信号上。 减小天线长度 天线长度与所接收的信号的波长正相关&#xff0c;调制到高频再发送能极大幅度降低接收成本。 避免信号干扰 利用调制将信号抬到不同的通频带&#xff0c;可以有效避免信号频率交叠的相…

Unity制作背包的格子

1.新建一个面板 2.点击面板并添加这个组件 3.点击UI创建一个原始图像&#xff0c;这样我们就会发现图像出现在了面板的左上角。 4.多复制几个并改变 Grid Layout Group的参数就可以实现下面的效果了

汽车信息安全硬件讨论:SE vs HSM

目录 1.什么是Secure Element 2.芯片内置HSM和SE 3.未来HSM的发展 现在的智能网联汽车看起来像是一个连接万物的智能移动终端&#xff0c;它不仅可以与OEM云服务器通信接收OTA推送&#xff0c;还可以与手机蓝牙、Wifi交互完成远程汽车解锁、座舱内环境设置等等&#xff0c;借…

2004年下半年软件设计师【下午题】试题及答案

文章目录 2004年下半年软件设计师下午题--试题2004年下半年软件设计师下午题--答案2004年下半年软件设计师下午题–试题

osgearth提示“simple.earth: file not handled”

在用vcpkg编译完osg和osgearth后&#xff0c;为了验证osgearth编译是否正确&#xff0c;进行测试&#xff0c;模型加载代码如下&#xff1a; root->addChild(osgDB::readNodeFile("simple.earth")); 此时以为是simple.earth路径的问题&#xff0c;遂改为以下代码…

手把手教程 | 云端部署语音合成神器——ChatTTS

近期&#xff0c;ChatTTS 凭借其高度仿真的 AI 语音合成技术迅速走红&#xff01;ChatTTS 是专为对话场景设计的文本转语音模型&#xff0c;例如 LLM 助手对话任务&#xff0c;支持中英文两种语言。其最大的模型在超过 10 万小时的中英文数据上进行训练&#xff0c;确保了高质量…

【机器学习300问】126、词嵌入(Word Embedding)是什么意思?

人类的文字&#xff0c;作为一种高度抽象化的符号系统&#xff0c;承载着丰富而复杂的信息。为了让电脑也能像人类一样理解并处理这些文字&#xff0c;科学家们不断探索各种方法&#xff0c;以期将人类的语言转化为计算机能够理解的格式。 一、One-Hot编码的不足 在自然语言处…

Sklearn中逻辑回归建模

分类模型的评估 回归模型的评估方法&#xff0c;主要有均方误差MSE&#xff0c;R方得分等指标&#xff0c;在分类模型中&#xff0c;我们主要应用的是准确率这个评估指标&#xff0c;除此之外&#xff0c;常用的二分类模型的模型评估指标还有召回率&#xff08;Recall&#xff…

Hedra:让您的照片说话

在数字内容创作的世界里&#xff0c;我们总是在寻找那些能够让我们的作品更加生动和吸引人的工具。Hedra软件就是这样一款工具&#xff0c;它能够让您的照片动起来&#xff0c;甚至说话。想象一下&#xff0c;您的家庭相册中的照片突然变得栩栩如生&#xff0c;或者您的产品图片…

反射机制详解

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a;Java从入门到精通 ✨特色专栏&#xff…

SYD881X读取GATT VALUE的长度

SYD881X读取GATT VALUE的长度 现在具体遇到这样一个需要&#xff0c;机器生产后要更新profile&#xff0c;这个只能够通过升级4K来做&#xff0c;但是需要知道profile是否改变了&#xff0c;这个就要知道profile是否改变来决定是否要升级&#xff0c;这里的做法是增加一个函数&…