為了對(duì)證券所的交易制度和股票的價(jià)格的機(jī)理進(jìn)行更加深刻的理解们童,在機(jī)緣巧合之下,我用python參考一篇論文【1】構(gòu)建了一個(gè)模擬的人工股票市場(chǎng)绘面,在這里給大家分享一下模型的搭建過(guò)程裁良,以便于感興趣的讀者進(jìn)行更深層次的研究。
1. 研究方法
隨著復(fù)雜性科學(xué)和計(jì)算機(jī)模擬技術(shù)的發(fā)展此叠,自20世紀(jì)90年代起,自上而下的多主體建模(基于主體的建模)方法開(kāi)始逐步被引入金融領(lǐng)域随珠,主要應(yīng)用于金融市場(chǎng)的微觀結(jié)構(gòu)和交易策略的研究灭袁,并因其依靠數(shù)學(xué)建模和人工模擬的方法創(chuàng)新成為金融市場(chǎng)研究的熱點(diǎn)。
本文擬基于多主體建模的方法窗看,自下而上地構(gòu)建貼近實(shí)際的人工股票市場(chǎng)茸歧,并且含有投資者的財(cái)富信息,以便研究股票市場(chǎng)中投資者的財(cái)富分布和演化显沈,或者對(duì)整體財(cái)富分布進(jìn)行基尼系數(shù)的測(cè)算软瞎。
2. 模型設(shè)計(jì)
為了簡(jiǎn)化模型的設(shè)計(jì)過(guò)程,假定市場(chǎng)中只有一支可以和現(xiàn)金交換的股票拉讯,股票在市場(chǎng)中的流通總數(shù)不變且無(wú)紅利發(fā)放涤浇,現(xiàn)金的收益率為0(即不存在時(shí)間價(jià)值,無(wú)法利用其持有的資金進(jìn)行其他投資)魔慷。
2.1 基本市場(chǎng)框架
中國(guó)證券交易采用計(jì)算機(jī)集合競(jìng)價(jià)和連續(xù)競(jìng)價(jià)兩種方式只锭,由于集合競(jìng)價(jià)在每日交易中占據(jù)的時(shí)間較短,并且參與主體也有所不同院尔,所以只關(guān)注每日交易中的連續(xù)競(jìng)價(jià)過(guò)程蜻展,直接用前一天的收盤價(jià)作為當(dāng)天開(kāi)盤價(jià)的近似,并用最后一筆成交價(jià)格作為當(dāng)日的收盤價(jià)格邀摆。
具體地纵顾,關(guān)注人工股票市場(chǎng)的T個(gè)交易日,在每個(gè)交易日隧熙,市場(chǎng)中的N個(gè)投資者按隨機(jī)順序進(jìn)入片挂,并根據(jù)自己對(duì)股票未來(lái)價(jià)格的預(yù)測(cè)提交訂單。假定每個(gè)投資者每日有且僅有一次機(jī)會(huì)進(jìn)入市場(chǎng)贞盯,這樣以投資者的申報(bào)為間隔音念,每個(gè)交易日包含N個(gè)交易區(qū)間。市場(chǎng)根據(jù)投資者的申報(bào)按照價(jià)格優(yōu)先與時(shí)間優(yōu)先的順序撮合成交躏敢。未成交的訂單暫存在當(dāng)日的指令簿中闷愤,在交易日結(jié)束時(shí),仍未成交的訂單會(huì)被清空件余。
2.2 交易參與主體——異質(zhì)投資者
每日有N位投資者參與市場(chǎng)交易讥脐,與傳統(tǒng)金融理論所假設(shè)的同質(zhì)代理人不同,這里強(qiáng)調(diào)了三個(gè)異質(zhì)主體啼器,主要體現(xiàn)在根據(jù)自身的不同稟賦對(duì)股票未來(lái)價(jià)格有不同的預(yù)測(cè)及策略行為旬渠。
2.2.1 投資者的初始稟賦
投資者初始稟賦的不同在模型的初始設(shè)定時(shí)主要體現(xiàn)在兩個(gè)方面,一是投資者的風(fēng)險(xiǎn)厭惡程度不同端壳,以α(i)標(biāo)識(shí)告丢。它決定了投資者每次申購(gòu)時(shí)拿出多少比例的現(xiàn)有可利用財(cái)富進(jìn)行買賣報(bào)量,該比例假設(shè)服從均勻分布 α(i)~U[α1损谦,α2]; 二是投資者對(duì)信息資源的獲取與處理能力不同岖免。大致分為3類:1) 能夠獲取較為準(zhǔn)確的信息并有 較強(qiáng)處理能力的機(jī)構(gòu)投資者,體現(xiàn)在他們既能夠得到上市公司股票的較為準(zhǔn)確的價(jià)值信息vt照捡,又掌握通過(guò)以往市場(chǎng)信息推導(dǎo)價(jià)格變動(dòng)趨勢(shì)的技術(shù)手段颅湘。2) 僅能夠利用股票價(jià)格的歷史信息進(jìn)行處理并推導(dǎo)未來(lái)價(jià)格變動(dòng)趨勢(shì)的 趨勢(shì)交易者。現(xiàn)實(shí)中利用市場(chǎng)歷史信息進(jìn)行技術(shù)交易的種類繁多栗精,交易策略也很豐富闯参。這里僅采用最常見(jiàn)的趨勢(shì)交易作為初步探討。3)不以股市盈利為目標(biāo)的噪聲交易者悲立,該類交易者往往忽視股票市場(chǎng)中的所有信息赢赊,他們參與市場(chǎng)是為了流動(dòng)性或其它便利性的需求。 事實(shí)上级历,不同投資者進(jìn)入市場(chǎng)時(shí)的財(cái)富也不盡相同释移,而不同的財(cái)富會(huì)使得投資者可以進(jìn)行的交易種類(如有些交易會(huì)有資金的門檻)及摩擦費(fèi)用(如傭金、稅收等)有所差異寥殖,這自然會(huì)增加模型的維度及復(fù)雜性玩讳。為了簡(jiǎn)化,這里賦予所有投資者相同的財(cái)富(由現(xiàn)金與股票構(gòu)成)嚼贡。
2.2.2 投資者的策略行為
2.2.2.1投資者對(duì)未來(lái)價(jià)格的預(yù)測(cè)
依據(jù)投資者對(duì)信息資源的獲取稟賦與處理能力的不同熏纯,分別闡述機(jī)構(gòu)投資者、趨勢(shì)交易者與噪聲交易者3類不同投資者對(duì)未來(lái)價(jià)格的預(yù)測(cè)方式粤策。 第1類是機(jī)構(gòu)投資者樟澜。他們擁有最準(zhǔn)確的信息資源———股票的價(jià)值vt,可以進(jìn)行價(jià)值投資。該投資理念最早由格雷厄姆提出秩贰,其核心在于對(duì)企業(yè)價(jià)值的研究霹俺,認(rèn)為股票價(jià)格會(huì)圍繞其自身價(jià)值上下波動(dòng),即當(dāng)股價(jià)低于(高)于價(jià)值時(shí)將會(huì)上漲(下跌)毒费。據(jù)此丙唧,第i個(gè)機(jī)構(gòu)投資者在第t日采取價(jià)值投資時(shí)對(duì)當(dāng)日股票收盤價(jià)的預(yù)測(cè)pe 為式(1)所示:
的正態(tài)分布想际。然而,現(xiàn)階段中國(guó)股票市場(chǎng)還不夠成熟溪厘,很多機(jī)構(gòu)投資者也會(huì)捕捉某些明確的市場(chǎng)走勢(shì)胡本,順勢(shì)而為,采取趨勢(shì)追隨策略以獲取短期收益畸悬。據(jù)此侧甫,該文認(rèn)為機(jī)構(gòu)投資者有時(shí)也會(huì)根據(jù)市場(chǎng)走勢(shì)通過(guò)追隨趨勢(shì)預(yù)測(cè)價(jià)格,具體形式 如式(2)所示傻昙。
類似地闺骚,
既然機(jī)構(gòu)投資者在獲取上市公司的價(jià)值信息和分析市場(chǎng)的價(jià)格趨勢(shì)上都有能力與優(yōu)勢(shì)甜奄,那么具體到每日交 易柠横,機(jī)構(gòu)投資者選擇哪種方式來(lái)形成價(jià)格預(yù)測(cè)呢?一個(gè)最直觀的假設(shè)是看哪種預(yù)測(cè)方式給出的信號(hào)最為強(qiáng)烈或在近期表現(xiàn)得最好课兄。具體地牍氛,采取式(4)的形式。
其中sign()為一符號(hào)函數(shù)唉擂,當(dāng)前一日收盤價(jià)大于(小于)移動(dòng)均線值時(shí)餐屎,趨勢(shì)追隨者預(yù)測(cè)該趨勢(shì)仍會(huì)持續(xù),給出買入(賣出)的信號(hào)sign = 1(sign = -1)楔敌。而該信號(hào)是否準(zhǔn)確啤挎,要根據(jù)下一期真實(shí)實(shí)現(xiàn)的市場(chǎng)收益 rt = log(pt) - log(p(t-1))來(lái)判斷驻谆。但是因?yàn)楸酒跓o(wú)法知道市場(chǎng)的收盤價(jià)卵凑,因此采用往期數(shù)據(jù)的得分累計(jì)值來(lái)作為當(dāng)期分?jǐn)?shù)的參考。當(dāng)預(yù)測(cè)與真實(shí)價(jià)格同向變動(dòng)時(shí)胜臊,該趨勢(shì)追隨的技術(shù)分析方法獲得數(shù)量為市場(chǎng)收益的正的得分勺卢,表明其前一期的預(yù)測(cè)能夠?yàn)橥顿Y者帶來(lái)正的收益。而由于短期的趨勢(shì)追隨預(yù)測(cè) 易受到市場(chǎng)中隨機(jī)噪聲的影響象对,機(jī)構(gòu)投資者往往關(guān)注于該技術(shù)分析方法獲利的穩(wěn)定性黑忱。所以本文采取加權(quán)平均的 累積收益來(lái)計(jì)分。其權(quán)重 0 < < 1為一貼現(xiàn)因子勒魔,反映越近期的預(yù)測(cè)的準(zhǔn)確程度對(duì)其得分函數(shù)的影響越大甫煞。當(dāng)該累積得分Score(i)t > |ft| 時(shí),表明此時(shí)的市場(chǎng)形勢(shì)下追隨趨勢(shì)可能比價(jià)值投資更有獲利性冠绢,故機(jī)構(gòu)投資者會(huì)采取趨勢(shì)追隨來(lái)形成價(jià)格預(yù)測(cè)抚吠,即 g(i)t = 1 ,式(4)退化到式(2)的形式。反之弟胀,式(4)退化到式(3)的形式楷力。
第2類是趨勢(shì)交易者。他們無(wú)法獲得較為準(zhǔn)確的上市公司的價(jià)值信息(或成本太大)孵户,只能通過(guò)技術(shù)分析的手段依據(jù)近期價(jià)格趨勢(shì)推測(cè)未來(lái)價(jià)格萧朝,其具體形式如式(6):類似的,d(i)3為趨勢(shì)交易者利用趨勢(shì)信息推測(cè)未來(lái)價(jià)格的強(qiáng)烈程度夏哭,其分布假設(shè)為均勻分布检柬。與機(jī)構(gòu)投資者的趨勢(shì)追隨策略不同的是,d(i)3 > 0 表示趨勢(shì)追隨竖配,d(i)3 < 0 表示趨勢(shì)反轉(zhuǎn)(實(shí)際上何址,機(jī)構(gòu)投資者的反轉(zhuǎn)策略是通過(guò)價(jià)值投資來(lái)實(shí)現(xiàn)的)。移動(dòng)平均價(jià)格械念、觀測(cè)尺度头朱、時(shí)變的方差等與第一類投資者采取的分布相同。
第3類是噪聲交易者龄减,他們?yōu)榱藵M足自身流動(dòng)性或風(fēng)險(xiǎn)對(duì)沖的需求進(jìn)入市場(chǎng)项钮,并不通過(guò)股票市場(chǎng)信息來(lái)盈利,其對(duì)價(jià)格的預(yù)測(cè)由當(dāng)日的開(kāi)盤價(jià)(前一日的收盤價(jià))加上一個(gè)正態(tài)分布的隨機(jī)噪聲構(gòu)成。2.2.2.2 投資者的申購(gòu)行為
各類投資者根據(jù)自身的資源稟賦及信息處理能力形成價(jià)格預(yù)測(cè)后烁巫,便進(jìn)入市場(chǎng)參與交易署隘。由于目前中國(guó)證券交易主要由限價(jià)訂單構(gòu)成,所以本文只考慮限價(jià)訂單亚隙,由報(bào)價(jià)和報(bào)量?jī)刹糠謽?gòu)成磁餐。 對(duì)于報(bào)價(jià),當(dāng)投資者預(yù)測(cè)價(jià)格將會(huì)上漲(下跌)時(shí)阿弃,結(jié)合自己的預(yù)測(cè)及下單前觀測(cè)到的市場(chǎng)即時(shí)信息來(lái)進(jìn)行買入(賣出)報(bào)價(jià)诊霹,買(bid(i)t) 賣 (ask(i)t) 報(bào)價(jià)的具體形式分別見(jiàn)式(8),式(9):其中 c(i)(t-1) 與 s(i)(t-1) 分別為投資者在上一期(當(dāng)前可用)的現(xiàn)金財(cái)富與股票財(cái)富彤恶。
2.3 價(jià)格形成——連續(xù)雙向拍賣機(jī)制
各類投資者按隨機(jī)順序進(jìn)入市場(chǎng)下單钞钙,基于連續(xù)雙向拍賣的基本機(jī)制,采用上海證券交易所的規(guī)則來(lái)確定雙方的成交價(jià)格声离。具體地芒炼,進(jìn)入市場(chǎng)的訂單按價(jià)格優(yōu)先和時(shí)間優(yōu)先的準(zhǔn)則在訂單簿中排序,最優(yōu)買入申報(bào)價(jià)格為最 高買入申報(bào)價(jià)格术徊,記為B本刽;最優(yōu)賣出申報(bào)價(jià)格為最低賣出申報(bào)價(jià)格,記為 A赠涮。若新進(jìn)入的買單報(bào)價(jià)>= A, 則以 A 的價(jià)格成交子寓,即 q(現(xiàn)價(jià))= A; 若新進(jìn)入的賣單報(bào)價(jià)<=B,則以B的價(jià)格成交,即q(現(xiàn)價(jià)) = B笋除。若最優(yōu)買入申報(bào)價(jià)格與最優(yōu)賣出申報(bào)價(jià)格相同斜友,則q(現(xiàn)價(jià))= A= B。
當(dāng)所有投資者都陸續(xù)進(jìn)入市場(chǎng)完成一次申購(gòu)后垃它,一個(gè)交易日結(jié)束鲜屏。各類投資者根據(jù)各自的成交情況對(duì)自身的現(xiàn)金財(cái)富和股票財(cái)富進(jìn)行清算烹看,見(jiàn)式(10)。其中洛史,p(i) 與 q(i) 分別表示當(dāng)日第i個(gè)投資者在 時(shí)刻成交的成交價(jià)格與成交量惯殊。投資者每日的總財(cái)富為更新后的現(xiàn)金財(cái)富與以當(dāng)日收盤價(jià)結(jié)算的股票財(cái)富之和,即
至此也殖,模型封閉土思。隨著時(shí)間的推進(jìn),模型進(jìn)入下一期的循環(huán)忆嗜。
3. 模擬結(jié)果
假設(shè)每類投資者都有100人己儒,初始財(cái)富都為100股的股票+10000元,股票的初始價(jià)值為100元每股霎褐,且價(jià)值符合隨機(jī)游走過(guò)程址愿,模擬100天的結(jié)果如圖所示:當(dāng)然该镣,該模型中也包含了各類投資者的財(cái)富變化冻璃,對(duì)模型進(jìn)行適當(dāng)?shù)男薷模€可以考慮T+1制度损合、漲跌停等制度對(duì)財(cái)富分布省艳、價(jià)格分布的影響。這里給出源碼:
# -*- 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
# 構(gòu)造投資者類別嫁审,返回其對(duì)當(dāng)日收盤價(jià)的預(yù)測(cè)
def inv_1(pclose,score, v):
# 機(jī)構(gòu)投資者價(jià)值預(yù)測(cè)噪聲誤差
e2 = 0.5
e2 = random.normal(loc=0.0, scale=e2)
# 機(jī)構(gòu)投資者預(yù)測(cè)價(jià)格回復(fù)價(jià)值速度
d1 = random.uniform(0.2, 0.8)
# 機(jī)構(gòu)投資者預(yù)測(cè)價(jià)格追隨趨勢(shì)程度
d2 = random.uniform(0.2, 0.8)
# 計(jì)算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)
# 貼現(xiàn)因子跋炕,越靠近當(dāng)日對(duì)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):
# 趨勢(shì)交易者預(yù)測(cè)價(jià)格持續(xù)或反轉(zhuǎn)程度
d3 = random.uniform(-1.5, 1.5)
# 計(jì)算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):
# 噪聲交易者預(yù)測(cè)的噪聲標(biāo)準(zhǔn)差
e5 = 0.5
e5 = random.normal(loc=0, scale=e5)
pred = pclose[-1] + e5
if pred > 0:
pass
else:
pred = 0
return pred
# 三類交易者根據(jù)即時(shí)成交價(jià)格形成報(bào)價(jià)
def giveprice_1(pclose, pred, price):
callprice = 0
# 交易信號(hào)蒙幻,1 為買入報(bào)價(jià)舞蔽, -1 為賣出報(bào)價(jià)
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():
#三類投資者數(shù)量 n_1,n_2,n_3
n_1 = 100
n_2 = 100
n_3 = 100
# 投資者分類列表
list_1 = []
# 投資者資金列表
list_2 = []
# 投資者持有的股票數(shù)量列表
list_3 = []
# 投資者擁有的財(cái)富列表
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
# 執(zhí)行一天的交易過(guò)程
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])
# 按照隨機(jī)順序使得投資者進(jìn)入市場(chǎng)
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]
# 形成第一類投資者的報(bào)價(jià)典徊,分?jǐn)?shù)
respond = inv_1(pclose, score, v)
# 更新分?jǐn)?shù)
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)
# 判斷買入報(bào)價(jià)和賣出報(bào)價(jià)漆腌,1 為買入庙洼,-1為賣出
if callprice_1[1] == 1:
# 買入報(bào)量
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
# 將買入報(bào)價(jià)寫入買單蔫磨,在完成交易后更新成交量
buy.append([rd[i], callprice_1[0], quant])
# 尋找所有賣出報(bào)價(jià)低于買入報(bào)價(jià)的賣家報(bào)單祝拯,每完成一筆您没,更新持倉(cāng)量
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
# 將賣出報(bào)價(jià)寫入賣價(jià)報(bào)單厂僧,在完成交易后更新成交量
sold.append([rd[i], callprice_1[0], quant])
# 尋找所有買入報(bào)價(jià)高于賣出報(bào)價(jià)的買家報(bào)單扣草,每完成一筆,更新持倉(cāng)量
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)
# 更新分?jǐn)?shù)
preclose = pclose[-1]
price_now = price[-1]
pred_1 = respond
callprice_1 = giveprice_1(preclose, pred_1, price_now)
# 判斷買入報(bào)價(jià)和賣出報(bào)價(jià)颜屠,1 為買入辰妙,-1為賣出
if callprice_1[1] == 1:
# 買入報(bào)量
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
# 將買入報(bào)價(jià)寫入買單,在完成交易后更新成交量
buy.append([rd[i], callprice_1[0], quant])
# 尋找所有賣出報(bào)價(jià)低于買入報(bào)價(jià)的賣家報(bào)單甫窟,每完成一筆密浑,更新持倉(cāng)量
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
# 將賣出報(bào)價(jià)寫入賣價(jià)報(bào)單,在完成交易后更新成交量
sold.append([rd[i], callprice_1[0], quant])
# 尋找所有買入報(bào)價(jià)高于賣出報(bào)價(jià)的買家報(bào)單粗井,每完成一筆尔破,更新持倉(cāng)量
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)
# 判斷買入報(bào)價(jià)和賣出報(bào)價(jià)敬锐,1 為買入,-1為賣出
if callprice_1[1] == 1:
# 買入報(bào)量
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
# 將買入報(bào)價(jià)寫入買單呆瞻,在完成交易后更新成交量
buy.append([rd[i], callprice_1[0], quant])
# 尋找所有賣出報(bào)價(jià)低于買入報(bào)價(jià)的賣家報(bào)單台夺,每完成一筆,更新持倉(cāng)量
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
# 將賣出報(bào)價(jià)寫入賣價(jià)報(bào)單痴脾,在完成交易后更新成交量
sold.append([rd[i], callprice_1[0], quant])
# 尋找所有買入報(bào)價(jià)高于賣出報(bào)價(jià)的買家報(bào)單颤介,每完成一筆,更新持倉(cāng)量
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
# 更新最終財(cái)富赞赖,收盤價(jià)
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期取收盤價(jià)為100
pclose = [100 for i in range(100)]
# 價(jià)值的隨機(jī)游走分布
v = [100]
# 價(jià)值隨機(jī)游走標(biāo)準(zhǔn)差
e3 = 0.05
price = []
# 收益率
rate = []
investorinfo = generate_origin_info()
# 設(shè)定要運(yùn)行的期數(shù):
num = 100
for i in range(num):
value = v[-1]
# v為股票的價(jià)值滚朵,符合隨機(jī)游走過(guò)程,是個(gè)隨機(jī)變量
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當(dāng)前進(jìn)度:{:.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. 參考文獻(xiàn)
【1】高言, 李昭輝. 基于人工股票市場(chǎng)的財(cái)富分布及演化研究[J]. 復(fù)雜系統(tǒng)與復(fù)雜性科學(xué), 2015(1):17-27.