股票交易系统

效果展示,如下动图:

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

  • 买卖股票,股民可以自行选择股票的买入或卖出价格和股票的数量,但是用户不一定马上就交易成功,只有当股票价格低于买入价才有机会买入,高于卖出价才有机会卖出。所以需要做委托处理。所以我们通常说的是委托下单,而不是说下单。
  • 股票买卖以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.mzph.cn/pingmian/30797.shtml

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

相关文章

startActivity启动流程

从桌面点击应用图标开始到Activity创建并执行onCreate&#xff0c;activity的启动涉及到两个进程system_server(AMS所在进程)和Zygote(如果进程没有创建需要先创建) 下图是从点击图标开始执行startActivity&#xff0c;一直到ActivityTaskSupervisor&#xff0c;到ActivityTas…

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

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

Python爬虫小白入门(四)PhatomJS+Selenium篇下

一、前言 前文介绍了PhatomJS 和Selenium 的用法&#xff0c;工具准备完毕&#xff0c;我们来看看如何使用它们来改造我们之前写的小爬虫。 我们的目的是模拟页面下拉到底部&#xff0c;然后页面会刷出新的内容&#xff0c;每次会加载10张新图片。 大体思路是&#xff0c;用S…

RuoYi-Vue-Plus(vue3)点击字典详情页面报404

复现过程&#xff1a; 1.新增菜单目录&#xff0c;设置目录路由地址为data 2.打开字典管理 -》 点击字典数据 -》 页面404 路由地址不允许重复 如果设置的地址重复就把字典顶掉l 建菜单的时候 这个路由名称不要使用data 后添加的/data 默认首字母大写 name为Data 覆盖了字典详…

网络文化经营许可证:互联网时代的护航之舵

文网文由中国文化和旅游部&#xff08;原文化部&#xff09;颁发&#xff0c;旨在对网络文化活动进行规范管理&#xff0c;确保文化内容的健康积极。通过对文化市场的严格监管&#xff0c;文网文有效杜绝了低俗、违法、侵权等不良现象的发生。网络文化市场的良性发展&#xff0…

2024年【N1叉车司机】作业考试题库及N1叉车司机实操考试视频

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年N1叉车司机作业考试题库为正在备考N1叉车司机操作证的学员准备的理论考试专题&#xff0c;每个月更新的N1叉车司机实操考试视频祝您顺利通过N1叉车司机考试。 1、【多选题】《中华人民共和国特种设备安全法》第…

计算机专业毕设-springboot论坛系统

1 项目介绍 基于SSM的论坛网站&#xff1a;后端 SpringBoot、Mybatis&#xff0c;前端thymeleaf&#xff0c;具体功能如下&#xff1a; 基本功能&#xff1a;登录注册、修改个人信息、修改密码、修改头像查看帖子列表&#xff1a;按热度排序、按更新时间排序、查看周榜月榜查…

golang去掉前后空格

str : " ce s "str strings.TrimSpace(str)fmt.Printf("--%v--", str)

如何移植libwebsockets

libwebsockets是一个高性能的开源C语言库&#xff0c;专为实现WebSocket协议及相关的HTTP协议而设计。它不仅使开发者能够在客户端与服务器端轻松构建WebSocket连接&#xff0c;还可以用作标准HTTP服务器。WebSocket是一种在单个TCP连接上进行全双工通信的协议&#xff0c;可以…

卷积神经网络(CNN)理解

1、引言&#xff08;卷积概念&#xff09; 在介绍CNN中卷积概念之前&#xff0c;先介绍一个数字图像中“边缘检测edge detection”案例&#xff0c;以加深对卷积的认识。图中为大小8X8的灰度图片&#xff0c;图片中数值表示该像素的灰度值。像素值越大&#xff0c;颜色越亮&…

视觉应用线扫相机速度反馈(倍福CX7000PLC应用)

运动控制实时总线相关内容请参考运动控制专栏,这里不再赘述 1、运动控制常用单位u/s运动控制单位[u/s]介绍_运动控制 unit是什么单位-CSDN博客文章浏览阅读176次。运动控制很多手册上会写这样的单位,这里的u是英文单词unit的缩写,也就是单位的意思,所以这里的单位不是微米…

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 05:糖果机接口

这是一本老书&#xff0c;作者 Steve Maguire 在微软工作期间写了这本书&#xff0c;英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字&#xff0c;英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》&a…

Word 文本框技巧2则

1 调整大小 一种方法是&#xff0c;选中文本框&#xff0c;周围出现锚点&#xff0c;然后用鼠标拖动来调整大小&#xff1b; 精确按数值调整&#xff0c;在 格式 菜单下有多个分栏&#xff0c;一般最后一个分栏是 大小 &#xff1b;在此输入高度和宽度的数值&#xff0c;来调整…

MySQL的数据存储一定是基于硬盘吗?

一、典型回答 不是的&#xff0c;MySQL也可以基于内存的&#xff0c;即MySQL的内存表技术。它允许将数据和索引存储在内存中&#xff0c;从而提高了检验速度和修改数据的效率。优点包括具有快速响应的查询性能和节约硬盘存储空间。此外&#xff0c;使用内存表还可以实现更高的复…

【C++】类和对象(三)构造与析构

文章目录 一、类的6个默认成员函数二、 构造函数干嘛的&#xff1f;语法定义特性综上总结什么是默认构造函数&#xff1f; 三、析构函数干嘛的 &#xff1f;语法定义析构顺序 一、类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。空类中并不是真的什么…

Mac数据如何恢复?3 款最佳 Mac 恢复软件

如果您认为 Mac 上已删除的文件永远丢失了&#xff0c;那您就大错特错了&#xff01;实际上&#xff0c;即使您清空了 Mac 上的垃圾箱&#xff0c;也有许多解决方案可以帮助您恢复已删除的文件。最好的解决方案之一是 Mac 恢复删除软件。最好的Mac 恢复删除应用程序可以轻松准确…

反射机制详解

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

SM9加密算法:安全、高效的国产密码技术

随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显。加密算法作为保障信息安全的核心技术&#xff0c;受到了广泛关注。在我国&#xff0c;一种名为SM9的加密算法逐渐崭露头角&#xff0c;凭借其卓越的安全性能和高效计算能力&#xff0c;成为了新一代国产密码技术的代表…

常用的Java日志框架:Log4j、SLF4J和Logback

日志是软件开发中不可或缺的一部分&#xff0c;它有助于记录应用程序的运行状态、调试问题和监控系统。Java中有多个流行的日志框架&#xff0c;如Log4j、SLF4J和Logback。 一、Log4j 1.1 什么是Log4j&#xff1f; Log4j是Apache基金会开发的一个开源日志框架&#xff0c;它…

Milvus跨集群数据迁移

将 Milvus 数据从 A 集群&#xff08;K8S集群&#xff09;迁到 B 集群&#xff08;K8S集群&#xff09;&#xff0c;解决方案很多&#xff0c;这里提供一个使用官方 milvus-backup 工具进行数据迁移的方案。 注意&#xff1a;此方案为非实时同步方案&#xff0c;但借助 MinIO 客…