股票交易系统

news2024/11/24 8:02:07

效果展示,如下动图:

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

  • 买卖股票,股民可以自行选择股票的买入或卖出价格和股票的数量,但是用户不一定马上就交易成功,只有当股票价格低于买入价才有机会买入,高于卖出价才有机会卖出。所以需要做委托处理。所以我们通常说的是委托下单,而不是说下单。
  • 股票买卖以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("待买入   ");
				}
				else
					color(124); printf("交易成功");
				SetPos(87, 22 + i); printf("数量:%d股", head->sm); color(112);
			}
			else
			{
				if (head->en == SellWait)
				{
					color(121); printf("待卖出   ");
				}
				else
					color(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;
		else
			head = 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.coloradmin.cn/o/1830986.html

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

相关文章

用户运营(1):从“麦肯锡三层面法”看怎么定“用户运营策略”

麦肯锡三层面法是源自麦肯锡公司提出的一种战略规划框架&#xff0c;它基于对全球不同行业高速增长公司的研究&#xff0c;为企业提供了一个系统化的方法&#xff0c;可以让企业用来平衡短期业绩、中期增长机会与长期潜力的开发&#xff0c;确保企业持续增长与适应市场变化。以…

springcloud第4季 分布式事务seata作用服务搭建

一 seata作用 1.1 作用 二 seata服务端搭建 2.1 seata搭建 2.2.1 seata 服务端下载安装 下载地址&#xff1a; Seata-Server下载 | Apache Seata 截图如下&#xff1a; 2.2.2 使用mysql初始化seata所需表 1.下载脚本地址&#xff1a;incubator-seata/script/server/db/…

分组检测常用算法

目录 4.分组检测常用算法4.1 接收信号能量检测4.2 双滑动窗口分组检测4.3 采用前导结构进行分组检测 总结 微信公众号获取更多FPGA相关源码&#xff1a; 4.分组检测常用算法 常用的分组检测算法包括能量检测算法、双滑动窗口能量检测算法、以及利用训练序列的同步算法等。 …

MySQL8新特性实现无限层级依赖SQL查询

前言 看IT老齐视频&#xff0c;学到了一招MySQL8的新特性&#xff0c;特此记录一下&#xff0c;大家可以去看原视频&#xff1a; 【IT老齐173】学到就是赚到&#xff0c;利用MySQL8新特性实现无限层级依赖SQL查询 准备 MySQL至少需要8以上的版本哦&#xff01; 1.创建表 C…

石墨消解仪 石墨炉加热 热传导率高 平均温差小

GS系列石墨消解仪是一款专为实验室加热设计制造的加热装置&#xff0c;可用于样品加热、培养、烘干。采用国际先进技术&#xff0c;具有消解快速、高效、节能、方便等优点&#xff0c;采用数字电路PID方式控制温度&#xff0c;更加准确。高纯优质石墨加热载体&#xff0c;表面喷…

代码随想录——电话号码的字母组合(Leetcode17)

题目链接 回溯 class Solution {List<String> res new ArrayList<String>();StringBuilder str new StringBuilder();HashMap<String, String> Sites new HashMap<String, String>();public List<String> letterCombinations(String digit…

《汇编语言程序设计》例子出现segmentation fault

照着例子抄写了一下&#xff0c;直接用的 gcc 编译&#xff0c;源码如下&#xff0c;因为不支持 pushl&#xff0c;所以改成了 pushq #cpuid.s View the CPUID Vendor ID string using C library calls .section .data output:.asciz "The processor Vendor ID is %s \n&…

揭秘:边缘智能网关P1600在智慧灯杆上的应用

智慧灯杆作为智慧城市建设的重要组成部分&#xff0c;集成了照明、通信、安防、环境监测等多重功能&#xff0c;是实现城市智能化的关键载体。边缘智能网关P1600在这一系统中扮演着至关重要的角色&#xff0c;它不仅连接和管理各种传感器和设备&#xff0c;还负责数据的采集、处…

python操作注册表没有权限(error:5拒绝访问)

在IDE中运行 1. Openkey( , , accesswinreg.KEY_ALL_ACCESS) 2. 管理员方式运行Vscode或PyCharm 如果要打包成应用呢&#xff1f; 怎么处理权限问题&#xff1f;

从Instance classifier重新思考多实例学习

弱监督的WSI分类通常被形式化为多实例学习&#xff08;MIL&#xff09;问题&#xff0c;其中每张slide都被视为一个bag&#xff0c;从中切出的patch被视为实例。现有的方法要么通过伪标记训练实例分类器&#xff0c;要么通过注意力机制将实例特征聚合为bag特征&#xff0c;然后…

【递归、搜索与回溯】综合练习二

综合练习二 1.组合2.目标和3.组合总和4.字母大小写全排列 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.组合 题目链接&#xff1a;77. 组…

电脑剪贴板历史记录查看,让你的信息管理更加有序!

剪贴板是电脑中一个非常实用的功能&#xff0c;允许用户在不同的应用程序之间复制和粘贴文本、图像、文件等内容。然而&#xff0c;默认情况下&#xff0c;剪贴板只能存储最近一次复制的内容&#xff0c;这可能会限制我们的工作效率。幸运的是&#xff0c;电脑剪贴板历史记录查…

MySQL中实现行列转换的示例

在 MySQL 中进行行列转换&#xff08;即&#xff0c;将某些列转换为行或将某些行转换为列&#xff09;通常涉及使用条件逻辑和聚合函数。虽然 MySQL 没有像 Oracle/SQL Server 中的 PIVOT 和 UNPIVOT 那样的直接功能&#xff0c;但你可以通过结合 CASE 语句、UNION 或 UNION AL…

c语言哈夫曼中英文混合编码

一.需求文档 c语言实现哈夫曼编码 1.中文编码 2.英文编码 3.中英文混合编码 4.从文件读取进行编码 5.编码生成编码文件 6.从生成的编码文件进行解码 二.运行截图

香港优才计划中介避坑,深圳哪家优才中介有实力?

随着香港优才计划取消配额限制以来&#xff0c;优才计划递交申请量骤增&#xff0c;许多DIY的申请人在递交申请后&#xff0c;长时间未能收到审批结果&#xff0c;甚至有人等待了12个月之久仍对审批进展一无所知。 而一些有中介协助的申请人&#xff0c;在等待审批的过程中&am…

如何在WIndows虚拟机安装 macOS 黑苹果系统?

在本教程中&#xff0c;我们将介绍如何在虚拟机上安装 macOS 黑苹果系统。黑苹果系统是非苹果公司官方支持的 macOS 系统的非官方版本&#xff0c;可以在普通 PC 上运行。请注意&#xff0c;安装黑苹果系统可能违反苹果的许可协议&#xff0c;请自行承担风险。参考视频教程&…

二、C#基本语法

C#是一种面向对象的编程语言。在面向对象的程序设计方法中&#xff0c;程序由各种相互交互的对象组成。相同种类的对象通常具有相同的类型&#xff0c;或者说&#xff0c;是相同的class中。 例如&#xff0c;以rectangle&#xff08;矩形&#xff09;对象为例。它具有length和…

有声读物管理平台Booksonic-Air

老苏最近在听评书&#xff0c;所以想找个软件来管理和收听&#xff0c;找了一圈&#xff0c;感觉 Booksonic-Air 可能能满足老苏的需求。 什么是 Booksonic-Air &#xff1f; Booksonic-Air 是一个用于流式传输有声读物的服务器&#xff0c;是原始 Booksonic 服务器的后继者。…

docker镜像拉取K8s的calico,Pod报错Init:ImagePullBackOff及kubekey生成离线包报错error: Pipeline[ArtifactExportpipe的解决

配置k8s集群出现问题 起初以为是版本问题&#xff0c;最后比对了一下发现没有问题。使用 kubectl describe calico-node-mg9xh -n kube-system命令查看发现docker pull 镜像失败&#xff0c;但是docker国内镜像源早就配置过了。 猜测Docker的缓存可能会导致拉取镜像失败。尝试…

深入探究MySQL的B+树索引

一、索引概述 在MySQL中&#xff0c;索引是一种数据结构&#xff0c;它可以帮助数据库系统更快地检索数据。索引可以比作一本书的目录&#xff0c;它可以让我们不必翻阅整本书就能找到所需的信息。没有索引&#xff0c;MySQL必须从头到尾扫描整个表来找到相关的行&#xff0c;…