为了对证券所的交易制度和股票的价格的机理进行更加深刻的理解,在机缘巧合之下,我用python参考一篇论文【1】构建了一个模拟的人工股票市场,在这里给大家分享一下模型的搭建过程,以便于感兴趣的读者进行更深层次的研究。
1. 研究方法
随着复杂性科学和计算机模拟技术的发展,自20世纪90年代起,自上而下的多主体建模(基于主体的建模)方法开始逐步被引入金融领域,主要应用于金融市场的微观结构和交易策略的研究,并因其依靠数学建模和人工模拟的方法创新成为金融市场研究的热点。
本文拟基于多主体建模的方法,自下而上地构建贴近实际的人工股票市场,并且含有投资者的财富信息,以便研究股票市场中投资者的财富分布和演化,或者对整体财富分布进行基尼系数的测算。
2. 模型设计
为了简化模型的设计过程,假定市场中只有一支可以和现金交换的股票,股票在市场中的流通总数不变且无红利发放,现金的收益率为0(即不存在时间价值,无法利用其持有的资金进行其他投资)。
2.1 基本市场框架
中国证券交易采用计算机集合竞价和连续竞价两种方式,由于集合竞价在每日交易中占据的时间较短,并且参与主体也有所不同,所以只关注每日交易中的连续竞价过程,直接用前一天的收盘价作为当天开盘价的近似,并用最后一笔成交价格作为当日的收盘价格。
具体地,关注人工股票市场的T个交易日,在每个交易日,市场中的N个投资者按随机顺序进入,并根据自己对股票未来价格的预测提交订单。假定每个投资者每日有且仅有一次机会进入市场,这样以投资者的申报为间隔,每个交易日包含N个交易区间。市场根据投资者的申报按照价格优先与时间优先的顺序撮合成交。未成交的订单暂存在当日的指令簿中,在交易日结束时,仍未成交的订单会被清空。
2.2 交易参与主体——异质投资者
每日有N位投资者参与市场交易,与传统金融理论所假设的同质代理人不同,这里强调了三个异质主体,主要体现在根据自身的不同禀赋对股票未来价格有不同的预测及策略行为。
2.2.1 投资者的初始禀赋
投资者初始禀赋的不同在模型的初始设定时主要体现在两个方面,一是投资者的风险厌恶程度不同,以α(i)标识。它决定了投资者每次申购时拿出多少比例的现有可利用财富进行买卖报量,该比例假设服从均匀分布 α(i)~U[α1,α2]; 二是投资者对信息资源的获取与处理能力不同。大致分为3类:1) 能够获取较为准确的信息并有 较强处理能力的机构投资者,体现在他们既能够得到上市公司股票的较为准确的价值信息vt,又掌握通过以往市场信息推导价格变动趋势的技术手段。2) 仅能够利用股票价格的历史信息进行处理并推导未来价格变动趋势的 趋势交易者。现实中利用市场历史信息进行技术交易的种类繁多,交易策略也很丰富。这里仅采用最常见的趋势交易作为初步探讨。3)不以股市盈利为目标的噪声交易者,该类交易者往往忽视股票市场中的所有信息,他们参与市场是为了流动性或其它便利性的需求。 事实上,不同投资者进入市场时的财富也不尽相同,而不同的财富会使得投资者可以进行的交易种类(如有些交易会有资金的门槛)及摩擦费用(如佣金、税收等)有所差异,这自然会增加模型的维度及复杂性。为了简化,这里赋予所有投资者相同的财富(由现金与股票构成)。
2.2.2 投资者的策略行为
2.2.2.1投资者对未来价格的预测
依据投资者对信息资源的获取禀赋与处理能力的不同,分别阐述机构投资者、趋势交易者与噪声交易者3类不同投资者对未来价格的预测方式。 第1类是机构投资者。他们拥有最准确的信息资源———股票的价值vt,可以进行价值投资。该投资理念最早由格雷厄姆提出,其核心在于对企业价值的研究,认为股票价格会围绕其自身价值上下波动,即当股价低于(高)于价值时将会上涨(下跌)。据此,第i个机构投资者在第t日采取价值投资时对当日股票收盘价的预测pe 为式(1)所示:
的正态分布。然而,现阶段中国股票市场还不够成熟,很多机构投资者也会捕捉某些明确的市场走势,顺势而为,采取趋势追随策略以获取短期收益。据此,该文认为机构投资者有时也会根据市场走势通过追随趋势预测价格,具体形式 如式(2)所示。
类似地,
既然机构投资者在获取上市公司的价值信息和分析市场的价格趋势上都有能力与优势,那么具体到每日交 易,机构投资者选择哪种方式来形成价格预测呢?一个最直观的假设是看哪种预测方式给出的信号最为强烈或在近期表现得最好。具体地,采取式(4)的形式。
其中sign()为一符号函数,当前一日收盘价大于(小于)移动均线值时,趋势追随者预测该趋势仍会持续,给出买入(卖出)的信号sign = 1(sign = -1)。而该信号是否准确,要根据下一期真实实现的市场收益 rt = log(pt) - log(p(t-1))来判断。但是因为本期无法知道市场的收盘价,因此采用往期数据的得分累计值来作为当期分数的参考。当预测与真实价格同向变动时,该趋势追随的技术分析方法获得数量为市场收益的正的得分,表明其前一期的预测能够为投资者带来正的收益。而由于短期的趋势追随预测 易受到市场中随机噪声的影响,机构投资者往往关注于该技术分析方法获利的稳定性。所以本文采取加权平均的 累积收益来计分。其权重 0 < < 1为一贴现因子,反映越近期的预测的准确程度对其得分函数的影响越大。当该累积得分Score(i)t > |ft| 时,表明此时的市场形势下追随趋势可能比价值投资更有获利性,故机构投资者会采取趋势追随来形成价格预测,即 g(i)t = 1 ,式(4)退化到式(2)的形式。反之,式(4)退化到式(3)的形式。
第2类是趋势交易者。他们无法获得较为准确的上市公司的价值信息(或成本太大),只能通过技术分析的手段依据近期价格趋势推测未来价格,其具体形式如式(6):类似的,d(i)3为趋势交易者利用趋势信息推测未来价格的强烈程度,其分布假设为均匀分布。与机构投资者的趋势追随策略不同的是,d(i)3 > 0 表示趋势追随,d(i)3 < 0 表示趋势反转(实际上,机构投资者的反转策略是通过价值投资来实现的)。移动平均价格、观测尺度、时变的方差等与第一类投资者采取的分布相同。
第3类是噪声交易者,他们为了满足自身流动性或风险对冲的需求进入市场,并不通过股票市场信息来盈利,其对价格的预测由当日的开盘价(前一日的收盘价)加上一个正态分布的随机噪声构成。2.2.2.2 投资者的申购行为
各类投资者根据自身的资源禀赋及信息处理能力形成价格预测后,便进入市场参与交易。由于目前中国证券交易主要由限价订单构成,所以本文只考虑限价订单,由报价和报量两部分构成。 对于报价,当投资者预测价格将会上涨(下跌)时,结合自己的预测及下单前观测到的市场即时信息来进行买入(卖出)报价,买(bid(i)t) 卖 (ask(i)t) 报价的具体形式分别见式(8),式(9):其中 c(i)(t-1) 与 s(i)(t-1) 分别为投资者在上一期(当前可用)的现金财富与股票财富。
2.3 价格形成——连续双向拍卖机制
各类投资者按随机顺序进入市场下单,基于连续双向拍卖的基本机制,采用上海证券交易所的规则来确定双方的成交价格。具体地,进入市场的订单按价格优先和时间优先的准则在订单簿中排序,最优买入申报价格为最 高买入申报价格,记为B;最优卖出申报价格为最低卖出申报价格,记为 A。若新进入的买单报价>= A, 则以 A 的价格成交,即 q(现价)= A; 若新进入的卖单报价<=B,则以B的价格成交,即q(现价) = B。若最优买入申报价格与最优卖出申报价格相同,则q(现价)= A= B。
当所有投资者都陆续进入市场完成一次申购后,一个交易日结束。各类投资者根据各自的成交情况对自身的现金财富和股票财富进行清算,见式(10)。其中,p(i) 与 q(i) 分别表示当日第i个投资者在 时刻成交的成交价格与成交量。投资者每日的总财富为更新后的现金财富与以当日收盘价结算的股票财富之和,即
至此,模型封闭。随着时间的推进,模型进入下一期的循环。
3. 模拟结果
假设每类投资者都有100人,初始财富都为100股的股票+10000元,股票的初始价值为100元每股,且价值符合随机游走过程,模拟100天的结果如图所示:当然,该模型中也包含了各类投资者的财富变化,对模型进行适当的修改,还可以考虑T+1制度、涨跌停等制度对财富分布、价格分布的影响。这里给出源码:
# -*- coding: utf-8 -*-
# @Time : 2019/3/5 16:23
# @Author : Arron Zhang
# @Email : 549144697@qq.com
# @File : Simulation of Stock Market.py
# @Software: PyCharm
import math
import matplotlib.pyplot as plt
from numpy import random
import numpy as np
import pandas as pd
from itertools import chain
from math import e, log
# 构造投资者类别,返回其对当日收盘价的预测
def inv_1(pclose,score, v):
# 机构投资者价值预测噪声误差
e2 = 0.5
e2 = random.normal(loc=0.0, scale=e2)
# 机构投资者预测价格回复价值速度
d1 = random.uniform(0.2, 0.8)
# 机构投资者预测价格追随趋势程度
d2 = random.uniform(0.2, 0.8)
# 计算N日的均值
N = random.randint(2, 30)
ma = np.sum(pclose[-(N+1): -1])/N
vmean = 0
for i in range(N):
a = i+1
vmean = (pclose[-(a+1)] - ma)**2 + vmean
mean = vmean/N
mean = mean**0.5
e1 = random.normal(loc=0,scale=mean)
# 贴现因子,越靠近当日对score的影响越大
sigma = 0.9
# 上期收益率
r = math.log10(pclose[-1]) - math.log10(pclose[-2])
sign = 0
if r > 0:
sign = 1
elif r <= 0:
sign = -1
score = sign * (pclose[-2] - ma) * r + sigma * score
f = math.log10(v[-2]) - math.log10(pclose[-2])
g = 0
if score > abs(f):
g = 1
elif score <= abs(f):
g = 0
pred = pclose[-2] + g*(d2*(pclose[-2] - ma)+e1) + (1 - g)*(d1*(v[-2] - pclose[-2]) + e2)
if pred > 0:
pass
else:
pred = 0
return [pred, score]
def inv_2(pclose):
# 趋势交易者预测价格持续或反转程度
d3 = random.uniform(-1.5, 1.5)
# 计算N日的均值
if len(pclose) >= 30:
N = random.randint(2, 31)
else:
N = random.randint(1, len(pclose) + 1)
ma = np.sum(pclose[-N:]) / N
vmean = 0
for i in range(N):
a = i + 1
vmean = (pclose[-a] - ma) ** 2 + vmean
mean = vmean / N
mean = mean**0.5
e4 = random.normal(loc=0, scale=mean)
pred = pclose[-1] + d3*(pclose[-1] - ma) + e4
if pred > 0:
pass
else:
pred = 0
return pred
def inv_3(pclose):
# 噪声交易者预测的噪声标准差
e5 = 0.5
e5 = random.normal(loc=0, scale=e5)
pred = pclose[-1] + e5
if pred > 0:
pass
else:
pred = 0
return pred
# 三类交易者根据即时成交价格形成报价
def giveprice_1(pclose, pred, price):
callprice = 0
# 交易信号,1 为买入报价, -1 为卖出报价
tradesign = 0
if pred > pclose:
tradesign = 1
if pred > price:
callprice = random.uniform(price,pred)
else:
callprice = random.uniform(pclose,pred)
elif pred <= pclose:
tradesign = -1
if pred > price:
callprice = random.uniform(pred, pclose)
else:
callprice = random.uniform(pred, price)
if callprice > 0:
pass
else:
giveprice_1(pclose, pred, price)
return [callprice, tradesign]
# 生成初始的投资者信息
def generate_origin_info():
#三类投资者数量 n_1,n_2,n_3
n_1 = 100
n_2 = 100
n_3 = 100
# 投资者分类列表
list_1 = []
# 投资者资金列表
list_2 = []
# 投资者持有的股票数量列表
list_3 = []
# 投资者拥有的财富列表
list_4 = []
# 投资者使用的方法得分
list_5 = []
for i in range(n_1):
list_1.append(1)
for i in range(n_2):
list_1.append(2)
for i in range(n_3):
list_1.append(3)
n = n_2 + n_1 + n_3
for i in range(n):
list_2.append(10000)
list_3.append(100)
list_4.append(20000)
list_5.append(0)
dictionary = {'type': list_1, 'money': list_2, 'volume': list_3, 'fortune': list_4, 'score': list_5}
primeinfo = pd.DataFrame(dictionary)
return primeinfo
# 执行一天的交易过程
def buy_sold_a_day(investorinfo, pclose, v):
buy = [[len(investorinfo) + 1, 0, 0]]
sold = [[len(investorinfo) + 1, 10000, 0]]
price = []
price.append(pclose[-1])
# 按照随机顺序使得投资者进入市场
rd = []
for i in range(len(investorinfo)):
rd.append(i)
random.shuffle(rd)
for i in range(len(rd)):
candidate = investorinfo.iloc[rd[i]]
# 第一类投资者
if candidate[0] == 1:
score = candidate[4]
# 形成第一类投资者的报价,分数
respond = inv_1(pclose, score, v)
# 更新分数
investorinfo.iloc[rd[i], 4] = respond[1]
preclose = pclose[-1]
price_now = price[-1]
pred_1 = respond[0]
callprice_1 = giveprice_1(preclose, pred_1, price_now)
# 判断买入报价和卖出报价,1 为买入,-1为卖出
if callprice_1[1] == 1:
# 买入报量
money_now = candidate[1]
if money_now > 0:
afa = random.uniform(0.25, 0.85)
quant = int(afa * (money_now / callprice_1[0]))
q_origin = quant
# 最终成交量
q = 0
sold.sort(key=lambda x: x[1])
j = 0
# 将买入报价写入买单,在完成交易后更新成交量
buy.append([rd[i], callprice_1[0], quant])
# 寻找所有卖出报价低于买入报价的卖家报单,每完成一笔,更新持仓量
while sold[j][1] <= callprice_1[0]:
if sold[j][2] >= quant and quant> 0:
sold[j][2] = sold[j][2] - quant
q = q + quant
if quant > 0:
price.append(sold[j][1])
investorinfo.iloc[sold[j][0], 1] = investorinfo.copy().iloc[sold[j][0], 1] + quant*sold[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] - quant * sold[j][1]
investorinfo.iloc[sold[j][0], 2] = investorinfo.copy().iloc[sold[j][0], 2] - quant
quant = 0
else:
pass
elif sold[j][2] < quant and sold[j][2] > 0:
quant = quant - sold[j][2]
q = q + sold[j][2]
if sold[j][2] > 0:
price.append(sold[j][1])
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] - sold[j][2] * sold[j][1]
investorinfo.iloc[sold[j][0], 1] = investorinfo.copy().iloc[sold[j][0], 1] + sold[j][2] * sold[j][1]
investorinfo.iloc[sold[j][0], 2] = investorinfo.copy().iloc[sold[j][0], 2] - sold[j][2]
sold[j][2] = 0
if j + 1 >= len(sold):
break
else:
j = j + 1
buy[-1][2] = q_origin - q
investorinfo.iloc[rd[i], 2] = investorinfo.copy().iloc[rd[i], 2] + q
else:
pass
elif callprice_1[1] == -1:
if candidate[2] > 0:
afa = random.uniform(0.25, 0.85)
quant = int(afa * candidate[2])
q_origin = quant
# 最终成交量
q = 0
buy.sort(key=lambda x: x[1], reverse=True)
j = 0
# 将卖出报价写入卖价报单,在完成交易后更新成交量
sold.append([rd[i], callprice_1[0], quant])
# 寻找所有买入报价高于卖出报价的买家报单,每完成一笔,更新持仓量
while buy[j][1] >= callprice_1[0]:
if buy[j][2] >= quant and quant > 0:
buy[j][2] = buy[j][2] - quant
q = q + quant
if quant > 0:
price.append(buy[j][1])
investorinfo.iloc[buy[j][0], 1] = investorinfo.copy().iloc[buy[j][0], 1] - quant * buy[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] + quant * buy[j][1]
investorinfo.iloc[buy[j][0], 2] = investorinfo.copy().iloc[buy[j][0], 2] + quant
quant = 0
else:
pass
elif buy[j][2] < quant and buy[j][2] > 0:
quant = quant - buy[j][2]
q = q + buy[j][2]
if buy[j][2] > 0:
price.append(buy[j][1])
investorinfo.iloc[buy[j][0], 1] = investorinfo.copy().iloc[buy[j][0], 1] - buy[j][2] * buy[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] + buy[j][2] * buy[j][1]
investorinfo.iloc[buy[j][0], 2] = investorinfo.copy().iloc[buy[j][0], 2] + buy[j][2]
else:
pass
buy[j][2] = 0
if j + 1 >= len(buy):
break
else:
j = j + 1
sold[-1][2] = q_origin - q
investorinfo.iloc[rd[i], 2] = investorinfo.copy().iloc[rd[i], 2] - q
else:
pass
# 第二类投资者
elif candidate[0] == 2:
respond = inv_2(pclose)
# 更新分数
preclose = pclose[-1]
price_now = price[-1]
pred_1 = respond
callprice_1 = giveprice_1(preclose, pred_1, price_now)
# 判断买入报价和卖出报价,1 为买入,-1为卖出
if callprice_1[1] == 1:
# 买入报量
money_now = candidate[1]
if money_now > 0:
afa = random.uniform(0.25, 0.85)
quant = int(afa * money_now / callprice_1[0])
q_origin = quant
# 最终成交量
q = 0
sold.sort(key=lambda x: x[1])
j = 0
# 将买入报价写入买单,在完成交易后更新成交量
buy.append([rd[i], callprice_1[0], quant])
# 寻找所有卖出报价低于买入报价的卖家报单,每完成一笔,更新持仓量
while sold[j][1] <= callprice_1[0]:
if sold[j][2] >= quant and quant > 0:
sold[j][2] = sold[j][2] - quant
q = q + quant
if quant > 0:
price.append(sold[j][1])
investorinfo.iloc[sold[j][0], 1] = investorinfo.copy().iloc[sold[j][0], 1] + quant*sold[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] - quant * sold[j][1]
investorinfo.iloc[sold[j][0], 2] = investorinfo.copy().iloc[sold[j][0], 2] - quant
quant = 0
else:
pass
elif sold[j][2] < quant and sold[j][2] > 0:
quant = quant - sold[j][2]
q = q + sold[j][2]
if sold[j][2] > 0:
price.append(sold[j][1])
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] - sold[j][2] * sold[j][1]
investorinfo.iloc[sold[j][0], 1] = investorinfo.copy().iloc[sold[j][0], 1] + sold[j][2] * sold[j][1]
investorinfo.iloc[sold[j][0], 2] = investorinfo.copy().iloc[sold[j][0], 2] - sold[j][2]
sold[j][2] = 0
if j + 1 >= len(sold):
break
else:
j = j + 1
buy[-1][2] = q_origin - q
investorinfo.iloc[rd[i], 2] = investorinfo.copy().iloc[rd[i], 2] + q
else:
pass
elif callprice_1[1] == -1:
if candidate[2] > 0:
afa = random.uniform(0.25, 0.85)
quant = int(afa * candidate[2])
q_origin = quant
# 最终成交量
q = 0
buy.sort(key=lambda x: x[1], reverse=True)
j = 0
# 将卖出报价写入卖价报单,在完成交易后更新成交量
sold.append([rd[i], callprice_1[0], quant])
# 寻找所有买入报价高于卖出报价的买家报单,每完成一笔,更新持仓量
while buy[j][1] >= callprice_1[0]:
if buy[j][2] >= quant and quant > 0:
buy[j][2] = buy[j][2] - quant
q = q + quant
if quant > 0:
price.append(buy[j][1])
investorinfo.iloc[buy[j][0], 1] = investorinfo.copy().iloc[buy[j][0], 1] - quant * buy[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] + quant * buy[j][1]
investorinfo.iloc[buy[j][0], 2] = investorinfo.copy().iloc[buy[j][0], 2] + quant
quant = 0
else:
pass
elif buy[j][2] < quant and buy[j][2] > 0:
quant = quant - buy[j][2]
q = q + buy[j][2]
if buy[j][2] > 0:
price.append(buy[j][1])
investorinfo.iloc[buy[j][0], 1] = investorinfo.copy().iloc[buy[j][0], 1] - buy[j][2] * buy[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] + buy[j][2] * buy[j][1]
investorinfo.iloc[buy[j][0], 2] = investorinfo.copy().iloc[buy[j][0], 2] + buy[j][2]
else:
pass
buy[j][2] = 0
if j + 1 >= len(buy):
break
else:
j = j + 1
sold[-1][2] = q_origin - q
investorinfo.iloc[rd[i], 2] = investorinfo.copy().iloc[rd[i], 2] - q
else:
pass
# 第三类投资者
elif candidate[0] == 3:
respond = inv_3(pclose)
preclose = pclose[-1]
price_now = price[-1]
pred_1 = respond
callprice_1 = giveprice_1(preclose, pred_1, price_now)
# 判断买入报价和卖出报价,1 为买入,-1为卖出
if callprice_1[1] == 1:
# 买入报量
money_now = candidate[1]
if money_now > 0:
afa = random.uniform(0.25, 0.85)
quant = int(afa * money_now / callprice_1[0])
q_origin = quant
# 最终成交量
q = 0
sold.sort(key=lambda x: x[1])
j = 0
# 将买入报价写入买单,在完成交易后更新成交量
buy.append([rd[i], callprice_1[0], quant])
# 寻找所有卖出报价低于买入报价的卖家报单,每完成一笔,更新持仓量
while sold[j][1] <= callprice_1[0]:
if sold[j][2] >= quant and quant > 0:
sold[j][2] = sold[j][2] - quant
q = q + quant
if quant > 0:
price.append(sold[j][1])
investorinfo.iloc[sold[j][0], 1] = investorinfo.copy().iloc[sold[j][0], 1] + quant*sold[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] - quant * sold[j][1]
investorinfo.iloc[sold[j][0], 2] = investorinfo.copy().iloc[sold[j][0], 2] - quant
quant = 0
else:
pass
elif sold[j][2] < quant and sold[j][2] > 0:
quant = quant - sold[j][2]
q = q + sold[j][2]
if sold[j][2] > 0:
price.append(sold[j][1])
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] - sold[j][2] * sold[j][1]
investorinfo.iloc[sold[j][0], 1] = investorinfo.copy().iloc[sold[j][0], 1] + sold[j][2] * sold[j][1]
investorinfo.iloc[sold[j][0], 2] = investorinfo.copy().iloc[sold[j][0], 2] - sold[j][2]
sold[j][2] = 0
if j + 1 >= len(sold):
break
else:
j = j + 1
buy[-1][2] = q_origin - q
investorinfo.iloc[rd[i], 2] = investorinfo.copy().iloc[rd[i], 2] + q
else:
pass
elif callprice_1[1] == -1:
if candidate[2] > 0:
afa = random.uniform(0.25, 0.85)
quant = int(afa * candidate[2])
q_origin = quant
# 最终成交量
q = 0
buy.sort(key=lambda x: x[1], reverse=True)
j = 0
# 将卖出报价写入卖价报单,在完成交易后更新成交量
sold.append([rd[i], callprice_1[0], quant])
# 寻找所有买入报价高于卖出报价的买家报单,每完成一笔,更新持仓量
while buy[j][1] >= callprice_1[0]:
if buy[j][2] >= quant and quant > 0:
buy[j][2] = buy[j][2] - quant
q = q + quant
if quant > 0:
price.append(buy[j][1])
investorinfo.iloc[buy[j][0], 1] = investorinfo.copy().iloc[buy[j][0], 1] - quant * buy[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] + quant * buy[j][1]
investorinfo.iloc[buy[j][0], 2] = investorinfo.copy().iloc[buy[j][0], 2] + quant
quant = 0
else:
pass
elif buy[j][2] < quant and buy[j][2] > 0:
quant = quant - buy[j][2]
q = q + buy[j][2]
if buy[j][2] > 0:
price.append(buy[j][1])
investorinfo.iloc[buy[j][0], 1] = investorinfo.copy().iloc[buy[j][0], 1] - buy[j][2] * buy[j][1]
investorinfo.iloc[rd[i], 1] = investorinfo.copy().iloc[rd[i], 1] + buy[j][2] * buy[j][1]
investorinfo.iloc[buy[j][0], 2] = investorinfo.copy().iloc[buy[j][0], 2] + buy[j][2]
else:
pass
buy[j][2] = 0
if j + 1 >= len(buy):
break
else:
j = j + 1
sold[-1][2] = q_origin - q
investorinfo.iloc[rd[i], 2] = investorinfo.copy().iloc[rd[i], 2] - q
else:
pass
# 更新最终财富,收盘价
rate = price[-1]/pclose[-1]
pclose = price[-1]
investorinfo['fortune'] = investorinfo.apply(lambda x: x['money'] + price[-1] * x['volume'], axis=1)
return investorinfo, pclose, price[1:], rate
# 前100期取收盘价为100
pclose = [100 for i in range(100)]
# 价值的随机游走分布
v = [100]
# 价值随机游走标准差
e3 = 0.05
price = []
# 收益率
rate = []
investorinfo = generate_origin_info()
# 设定要运行的期数:
num = 100
for i in range(num):
value = v[-1]
# v为股票的价值,符合随机游走过程,是个随机变量
n = random.normal(loc=0.0, scale=e3)
value = e**(log(value)+n)
v.append(value)
back = buy_sold_a_day(investorinfo, pclose, v)
investorinfo = back[0]
pclose.append(back[1])
price.append(back[2])
rate.append(back[3])
print('\r当前进度:{:.2f}%'.format((i+1) * 100 / num), end='')
print(investorinfo)
print(pclose)
print(rate)
price = list(chain.from_iterable(price))
print(price)
draw_pclose = pclose[99:]
x = np.linspace(0, num, 1)
plt.title('All Price that happened')
plt.xlabel('Times')
plt.ylabel('price')
plt.plot(price)
plt.show()
4. 参考文献
【1】高言, 李昭辉. 基于人工股票市场的财富分布及演化研究[J]. 复杂系统与复杂性科学, 2015(1):17-27.