public void InitializeBackBones(double[] a, double[] sigma) { Debug.Assert(a.Length == _times.Length && sigma.Length == _times.Length); /// 0, 1, ..., N 時点 分割数はN : N分割するとき、back boneはN個用いる _TreeBackBones[0] = new TreeBackBone(); _TreeBackBones[0].t = _times[0]; _TreeBackBones[0].a = a[0]; _TreeBackBones[0].sigma = sigma[0]; _TreeBackBones[0].dt = _times[1] - _times[0]; _TreeBackBones[0].dx = 0; _TreeBackBones[0].V = ComputeV(a[0], sigma[0], _TreeBackBones[0].dt); /// i = 1, ..., N - 1 for (int i = 1; i < GetTimeSeparationNumber(); ++i) { _TreeBackBones[i] = new TreeBackBone(); _TreeBackBones[i].t = _times[i]; _TreeBackBones[i].a = a[i]; _TreeBackBones[i].sigma = sigma[i]; _TreeBackBones[i].dt = _times[i + 1] - _times[i]; _TreeBackBones[i].dx = _TreeBackBones[i - 1].V * Math.Sqrt(3); _TreeBackBones[i].V = ComputeV(a[i], sigma[i], _TreeBackBones[i].dt); } int ii = GetTimeSeparationNumber(); _TreeBackBones[ii] = new TreeBackBone(); _TreeBackBones[ii].t = _times[ii]; _TreeBackBones[ii].a = a[ii]; _TreeBackBones[ii].sigma = sigma[ii]; _TreeBackBones[ii].dt = 0; _TreeBackBones[ii].dx = _TreeBackBones[ii - 1].V * Math.Sqrt(3); _TreeBackBones[ii].V = ComputeV(a[ii], sigma[ii], _TreeBackBones[ii].dt); }
/// <summary> /// 入力されたbondPriceに合わせるalpha[]を求め、rを設定する. /// </summary> /// <param name="bondPrices">ツリーの分割時点に対する割引債価格</param> public void FitToInputBondPrice(double[] bondPrices) { Debug.Assert(bondPrices.Length == _TreeBackBones.Length); /// alphaの算出 double initialAlpha = 0D; for (int i = 0; i < _TreeBackBones.Length - 1; ++i) { FitToInputBondPrice(i, bondPrices[i + 1], initialAlpha); if (_TreeBackBones[i].alpha == Double.NegativeInfinity) { initialAlpha = 0D; } initialAlpha = _TreeBackBones[i].alpha; } /// rの設定 for (int i = 0; i < bondPrices.Length - 1; ++i) { TreeBackBone bone = _TreeBackBones[i]; int jSize = bone.jMax - bone.jMin + 1; for (int j = 0; j < jSize; ++j) { _TreeNodes[i][j].r = ConvertToShortRate(bone.alpha, _TreeNodes[i][j].j * bone.dx); } } }
/// <summary> /// 時点iのalphaを時点i+1に対するpriceに合わせる /// </summary> /// <param name="i"></param> /// <param name="price"></param> /// <returns>収束誤差</returns> public double FitToInputBondPrice(int i, double price, double initialAlpha = 0D) { TreeBackBone bone = _TreeBackBones[i]; if (i == 0) { bone.alpha = Math.Log(-Math.Log(price, Math.E) / bone.dt, Math.E); double dummy; ComputeBondPrice(0, out dummy); ComputeBondPrice(1, out dummy); return(0D); } /// Newtow法 /// 誤差 double error = 1e-15; /// alphaの初期値 bone.alpha = initialAlpha; /// treeにより算出する価格 double priceByTree; do { /// priceByTree - priceに対するalphaの微分係数 double derivative; /// 時点i+1の価格を計算して時点iのalphaを決定する priceByTree = ComputeBondPrice(i + 1, out derivative); bone.alpha = bone.alpha - (priceByTree - price) / derivative; } while (Math.Abs(priceByTree - price) > error); return(Math.Abs(priceByTree - price)); }
public void OutputCsvTreeBackBones(string filepath) { using (var sw = new System.IO.StreamWriter(filepath, false)) { sw.WriteLine(TreeBackBone.ToStringValuesHeader()); for (int i = 0; i < _TreeBackBones.Length; ++i) { sw.WriteLine(_TreeBackBones[i].ToStringValues()); } } }
/// <summary> /// 計算済みの時点i-1ノードのQ値を用いてツリーによる割引債価格P(0,i)を算出&設定する. /// 引き続いて時点iに対する全ノードのQ値を計算する. /// </summary> /// <param name="i"></param> /// <param name="priceDerivativeAlpha">ツリーによる割引債価格のalphaによる微分係数</param> /// <returns>ツリーにより算出された割引債価格</returns> /// <remarks>i=0から順に呼び出すこと</remarks> public double ComputeBondPrice(int i, out double priceDerivativeAlpha) { priceDerivativeAlpha = 0; if (i == 0) { _TreeBackBones[0].bondPrice = 1D; _TreeNodes[0][0].Q = 1D; /// priceDerivativeAlphaは使わないのでダミー0を返す return(1D); } /// i-1時点データ TreeBackBone pBone = _TreeBackBones[i - 1]; TreeNode[] pNodes = _TreeNodes[i - 1]; int pNodeCount = pBone.jMax - pBone.jMin + 1; /// BondPrice BK tree double bondPrice = 0; for (int j = 0; j < pNodeCount; ++j) { double commonTerm = ConvertToShortRate(pBone.alpha, pNodes[j].j * pBone.dx) * pBone.dt; double priceTerm = pNodes[j].Q * Math.Exp(-commonTerm); bondPrice += priceTerm; priceDerivativeAlpha += priceTerm * commonTerm; } /// BondPrice BK tree /// 価格の微分係数そのものにしておくため, マイナスをつける priceDerivativeAlpha = -priceDerivativeAlpha; /// i時点のQ値の計算 /// i-1時点ノードを走査して, i時点の各ノードに対するQ値を一度に計算する TreeBackBone bone = _TreeBackBones[i]; TreeNode[] nodes = _TreeNodes[i]; int nodeCount = bone.jMax - bone.jMin + 1; /// i時点の各ノードに対するQ値の初期化 for (int j = 0; j < nodeCount; ++j) { nodes[j].Q = 0; } /// Q値の計算 for (int j = 0; j < pNodeCount; ++j) { /// down, mid, up nodeの順に集計 int kIndex = pNodes[j].k - bone.jMin; /// BK tree double temp = pNodes[j].Q * Math.Exp(-ConvertToShortRate(pBone.alpha, pNodes[j].j * pBone.dx) * pBone.dt); nodes[kIndex - 1].Q += pNodes[j].pd * temp; nodes[kIndex].Q += pNodes[j].pm * temp; nodes[kIndex + 1].Q += pNodes[j].pu * temp; } bone.bondPrice = bondPrice; return(bondPrice); }
/// <summary> /// ツリーノードの構築 /// </summary> /// <remarks>InitializeBackBonesを実行済みであること</remarks> public void SetUpTreeNodes() { /// Root Node _TreeNodes[0] = new TreeNode[1]; _TreeNodes[0][0] = new TreeNode(); _TreeNodes[0][0].Initialize(0, 0, Math.Exp(-_TreeBackBones[0].a * _TreeBackBones[0].dt) , _TreeBackBones[1].dx, _TreeBackBones[0].V, _TreeBackBones[0].V * _TreeBackBones[0].V); _TreeBackBones[0].jMin = 0; _TreeBackBones[0].jMax = 0; /// i = 1, 2, ..., N (Leaf Nodeに該当) int preNodeCount = 1; for (short i = 1; i < _times.Length; ++i) { /// i時点のTreeBackBone TreeBackBone ithBone = _TreeBackBones[i]; /// jMin, jMaxの取得 ithBone.jMax = (short)(_TreeNodes[i - 1][preNodeCount - 1].k + 1); ithBone.jMin = (short)(_TreeNodes[i - 1][0].k - 1); /// i時点のノード数 int nodeCount = ithBone.jMax - ithBone.jMin + 1; /// i時点のノードのnew _TreeNodes[i] = new TreeNode[nodeCount]; for (short j = 0; j < nodeCount; ++j) { _TreeNodes[i][j] = new TreeNode(); } /// 最終時点より前と最終時点で分ける if (i < GetTimeSeparationNumber()) { /// j = jMin, ..., jMax に対するnodeを順に初期化する /// j = jMin, ..., jMax に対応する配列index 0,1,...,nodeCount-1 TreeBackBone nextBone = _TreeBackBones[i + 1]; double expMinusADeltaT = Math.Exp(-ithBone.a * ithBone.dt); double V2 = ithBone.V * ithBone.V; for (short j = 0; j < nodeCount; ++j) { _TreeNodes[i][j].Initialize((short)(j + ithBone.jMin), ithBone.dx, expMinusADeltaT, nextBone.dx, ithBone.V, V2); } } else { for (short j = 0; j < nodeCount; ++j) { _TreeNodes[i][j].InitializeLeafNode((short)(j + ithBone.jMin), ithBone.dx); } } /// preNodeCount preNodeCount = nodeCount; } }
public void OutputCsvTreeNodes(string filepath) { using (var sw = new System.IO.StreamWriter(filepath, false)) { sw.WriteLine("i,{0}", TreeNode.ToStringValuesHeader()); for (int i = 0; i < _TreeBackBones.Length; ++i) { TreeBackBone bone = _TreeBackBones[i]; for (short j = 0; j < bone.jMax - bone.jMin + 1; ++j) { sw.Write("{0},", i); sw.WriteLine(_TreeNodes[i][j].ToStringValues()); } } } }