直接上程序代码了,大家直接看吧!
clear,clc;
global NUM_PATH NUM_T VOLA S0 RF
NUM_PATH=1000;%股票路径数
NUM_T=25;%时间点数目
DELT_T=3/25;%相邻时间点间隔时间(年)
S0=8.30;%初始股价
SZ=13.63;%转股价
VOLA=0.324;%股价年波动率
RF=0.0225;%无风险利率
START_T=2;%转换权允许行使起点
SELL_CON_DAY=20;%回售(即卖回)条款中规定的允许回售的连续天数
SELL_P=103;%回售价格
BUY_CON_DAY=20;%赎回条款中规定的赎回的连续天数
BUY_P=105;%赎回价格
s=get_paths(NUM_PATH,NUM_T,S0,VOLA,RF,DELT_T);%生成股价路径
sell_back_mat=get_sell_back_mat(s,SELL_CON_DAY,SELL_P,valid_d);
buy_back_mat =get_sell_back_mat(s,BUY_CON_DAY,BUY_P,valid_d);
save data;
%==========================================================================
function s_star=get_paths(NUM_PATH,NUM_T,S0,VOLA,RF,DELT_T)
%函数功能:生成股价路径
%输入参数:NUM_PATH:生成的路径数目,NUM_T:股票价格期数,S0:初始股价
%VOLA:股价波动率,RF:无风险利率(年),DETL_T:每期时间间隔(年)
%返回:s_star,股价路径矩阵(矩阵大小NUM_PATH*NUM_T)
eps=normrnd(0,l,NUM_PATH,NUM_T);%产生符合标准正态分布的乱数
s(l:NUM_PATH,1)=S0;%第1列全部置为初始股价
for i=l:NUM_PATH
for k=2:NUM_T
s(i,k)=s(i,k-l)*exp((RF-0.5*VOLA^2)*DETL_T+VOLA*eps(i,k)*DELT_T^0.5);
end
end
% EMS for stock price paths
s_tar(:,l)=s(:,l);
for tj=2:NUM_T
ztj=s_star(:,tj-l).*(s(:,tj)./s(:,tj-l));
z0tj=mean(ztj)*exp(-RF*(tl+(tj-2)*t2));
s_star(:,tj)=s_star(:,l).*(ztj/z0tj);
end
function sell_back_mat=get_sell_back_mat(s,continue_dates,sellback_sp,valid_d)
%函数功能:按照回售条款:回售生效日后,若某日前连续若干天的股价都低于约定股价,则该日有权卖回
%本函数根据日股价路径矩阵,确定哪些日期满足回售条件
%输入参数s:股价路径矩阵
%continue_dates:约定的连续天数
%sellback_sp:约定的股价
%valid_d:允许回售生效日
%注意:本函数假定valid_d总是大于continue_dates+l
%返回:返回值se!l_back_mat为一大小与股价路径矩阵相同的矩阵,
%其行表示路径,列表示交易日,各矩阵表示是否满足回售条件,O-不满足 1-满足
valid_d=max(valid_d,continue_dates+l);
rows=size(s,l);%计算行数(路径数)
cols=size(s,2);%计算列数(交易日数)
sell_back_mat(l:rows,l:valid_d)=0;%生效日前一律为0
for j=valid_d:cols
sell_back_mat(:,j)=sum(s(:,j-continue_dates:j-l)<sellback_sp,2)==continue_dates;
end
function buy_back_mat=get_buy_back_mat(s,continue_dates,buyback_sp,valid_d)
%函数功能:按照赎回条款:赎回生效日后,若某日前连续若干天的股价都高于约定股价,则该日有权赎回
%本函数根据日股价路径矩阵,确定哪些日期满足赎回条件
%输入参数:s:股价路径矩阵
%continue_dates:约定的连续天数
%buyback_sp:约定的股价
%valid_d:允许赎回生效日
%注意:本函数假定valid_d总是大于continue_dates+l
%返回:返回值buy_back_mat为一大小与股价路径矩阵相同的矩阵,
%其行表示路径,列表示交易日,各矩阵表示是否满足赎回条件,O-不满足 1-满足
valid_d=max(valid_d,continue_dates+l);
rows=size(s,l):%计算行数(路径数)
cols=size(s,2);%计算列数(交易日数)
buy_back_mat(l:rows,l:valid_d)=0;%生效日前一律为0
for j=valid_d:cols
buy_back_mat(:,j)=sum(s(:,j-continue_dates:j-l)>=buyback_sp,2)==continue_dates;
end
%程序二
function Bond_val=CB()
%==========================================================================
%可转债基本数据(注意这里全部设为全局变量)
global NOMINAL COUPON RF CREDIT_SPREED SZ VP CON_RATIO RATE STARI_T DELT_T
NOMNIAL=100;%可转债票面值
COUPON=l.5;%每期可转债息票
RF=0.0225;%无风险利率(年)
CREDIT_SPREAD=000.98;%债券信用利差
RATE=RF+CREDIT_SPREAD:%折现率
SZ=13.63;%转换价格
VP=103;%回售价格
CON_RATIO=NOMINAL/SZ;%可转债之转换比率
VOLA=0.324;%股价年波动率
S0=8.30;%标的股票发行日价格
START_T=2;%转换权允许行使起点
DELT_T=3/25;%相邻时间点间隔时间(年)
global NUM_PATH NUM_T VOLA S0
NUM_PATH=1000;%股票路径数
NUM_T=25;%时间点数目
load data;
cash_flow_mat(l:NUM_PATH,NUM_T)=NOMINAL;%以下三行计算可转债到期日理论价格
path_idx=who_maybe_convert(s(:,NUM_T),NUM_T);%找出转换价值超过纯粹债券价值的股票路径
cash_flow_mat(path_idx,NUM_T)=s(path_idx,NUM_T).*CON_RATIO;
for j=NUM_T-1:-1:START_T;%从倒数第2列开始倒推,直到允许执行开始列
path_idx=who_maybe_convert(s(:,j),j);%找出转换价值超过纯粹债券价值的股票路径
if isempty(path_idx)%若该列没有可转换的路径,则直接将下一时点的现金流折现
cash_flow_mat(:,j)=pvfix--con_rate(RATE,DETL_T,COUPON,cash_flow_mat(:,j+l));
continue;
end
Y=pvfix_con_rate(RATE,DELT_T,COUPON,cash_flow_mat(path_idx,j+1));%计算所选路径继续持有到下期时的现金流折现值
X=[s(path_idx,j),s(path_idx,j).^2,s(path_idx,j).^3];%生成回归所需X矩阵
X=[ones(length(path_idx),l),X];
warning 'off';
Beta=regress(Y,YX);
warning 'on';
e_val=X*Beta;%计算各条路径在当前不转换时的期望继续持有价值
convert_p=s(path_idx,j)*CON_RATIO;%所选路径的转换价值
convert_idx=find(e_val<convert_P);%确定要执行转换的路径。当期望继续持有价值小于转换价值时,该路径执行转换。
cash_flow_mat(:,j)=pvfix_con_rate(RATE,DELT_T,COUPON,cash_flow_mat(:,j+l));%更新现金流矩阵第j列
if ~isempty(convert_idx)
cash_flow_mat(path_idx(convert_idx),j)=convert_p(convert_idx);
cash_flow_mat(path_idx(convert_idx),j+l:NUM_T)=0;%执行了转换的债券,其后时点现金流都为0
end
sellback_path_idx=find(sell_back_mat(:,j) & cash_flow_mat(:,j)<VP);%找出满足卖回条件,且卖回价值高于转换价值和继续持有的折现值的路径
if ~isempty(sellback_path_idx)
cash_flow_mat(sellback_path_idx,j)=VP;%满足卖回条件的路径现金值赋值为卖回价值
cash_flow_mat(sellback_path_idx,j+l:NUM_T)=0;
end
buyback_path_idx=find(buy_back_mat(:,j));%找出满足赎回条件的路径
if ~isempty(sellback_path_idx)
cash_flow_mat(buyback_path_idx,j)=s(buyback_path_idx,j)*CON_RATIO;%满足赎回条件的路径现金值转股价值
cash_flow_mat(buyback_path_idx,j+l:NUM_T)=0;
end
end
cash_sum=O;
for i=l:NUM_PATH
pos=find(cash_flow_mat(i,START_T:NUM_T)==0,1,'first'):%找出现金流矩阵o的位置,这里pos是相对于SATRT_T而言的
if isempty(pos)%现金流矩阵中该路径SATRT_T列后没有0,则表明持有到最末为最优决策
pos=NUM_T;
else
pos=START_T+pos-2;%现金流矩阵中该路径SATRT_T列后有0,则其前1列即为最优决策时点,这里pos是achs_now_mat矩阵中的位置
end %将当前路径最优价值折现到期初并累加
cash_sum=cash_sum+pvfix_con_rate(RATE,(pos-1)*DETL_T,COUPON,cash_flow_mat(i,pos));
Bond_val=eash_sum/NUM_PATH;
end
%==========================================================================
function path_idx=who_maybe_convert(p,t)
%函数功能:判断指定时间点哪些路径满足转股条件,在该时间点投资者有可能会转股。
%本函数的判断方法是:若当前股价大于等于转股价,并且该时点转换价值高于纯债券价值,则认为满足转股条件,投资者可能会转股。
%输入参数:P:该时间点各条路径的股价列向量 t:指定的时间点
%返回:满足转股条件的路径索引号列向量
global RATE NUM_T DELT_T COUPON NOMINAL SZ CON_RATIO
bond_value=pvfix_con_rate(RATE,(NUM_T-t)*DELT_T,COUPON,NOMINAL);%纯债券价值
path_idx=find(p>SZ & p*CON_RATIO>bond_value);
%==========================================================================
function pv=pvfix_con_rate(rate,nper,p,fv)
%函数功能:按连续复利计算,等额分付的现金价值
%输入参数:rate:每周期利率 nper:周期数目 p:每周期支付额
%fv:最后期,除p外的支付额
%返回:pv现值
num_pay=floor(nper);
dix=nper-num_pay;
pv=p*exp(-rate)*exp(-dix*rate)*(l-exp(-num_pay*rate))/(l-exp(-rate))+fv*exp(-rate*nper);
|