private int sendpacker(OptionFunction function, CT2Packer packer, bool IsAsync = true) { try { CT2BizMessage BizMessage = new CT2BizMessage(); //构造消息 BizMessage.SetFunction((int)function); //设置功能号 BizMessage.SetPacketType(0); //设置消息类型为请求 unsafe { BizMessage.SetContent(packer.GetPackBuf(), packer.GetPackLen()); } /************************************************************************/ /* 此处使用异步发送 同步发送可以参考下面注释代码 * connection.SendBizMsg(BizMessage, 0); * 1=异步,0=同步 * /************************************************************************/ int iRet = this.connMain.SendBizMsg(BizMessage, (IsAsync) ? 1 : 0); if (iRet < 0) { MessageManager.GetInstance().Add(MessageType.Error, string.Format("发送错误:{0}", connMain.GetErrorMsg(iRet))); } packer.Dispose(); BizMessage.Dispose(); return(iRet); } catch (Exception ex) { throw ex; } }
public virtual void test_trinomialTree_down() { int nSteps = 133; LatticeSpecification lattice = new CoxRossRubinsteinLatticeSpecification(); DoubleArray rebate = DoubleArray.of(nSteps + 1, i => REBATE_AMOUNT); double barrierLevel = 76d; double tol = 1.0e-2; foreach (bool isCall in new bool[] { true, false }) { foreach (double strike in STRIKES) { foreach (double interest in INTERESTS) { foreach (double vol in VOLS) { foreach (double dividend in DIVIDENDS) { OptionFunction function = ConstantContinuousSingleBarrierKnockoutFunction.of(strike, TIME, PutCall.ofPut(!isCall), nSteps, BarrierType.DOWN, barrierLevel, rebate); SimpleConstantContinuousBarrier barrier = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, barrierLevel); double exact = REBATE_AMOUNT * REBATE_PRICER.price(SPOT, TIME, interest - dividend, interest, vol, barrier.inverseKnockType()) + BARRIER_PRICER.price(SPOT, strike, TIME, interest - dividend, interest, vol, isCall, barrier); double computed = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT, vol, interest, dividend); assertEquals(computed, exact, Math.Max(exact, 1d) * tol); } } } } } }
public virtual void test_trinomialTree() { int nSteps = 135; LatticeSpecification[] lattices = new LatticeSpecification[] { new CoxRossRubinsteinLatticeSpecification(), new TrigeorgisLatticeSpecification() }; double tol = 5.0e-3; foreach (bool isCall in new bool[] { true, false }) { foreach (double strike in STRIKES) { foreach (double interest in INTERESTS) { foreach (double vol in VOLS) { foreach (double dividend in DIVIDENDS) { OptionFunction function = EuropeanVanillaOptionFunction.of(strike, TIME, PutCall.ofPut(!isCall), nSteps); double exact = BlackScholesFormulaRepository.price(SPOT, strike, TIME, vol, interest, interest - dividend, isCall); foreach (LatticeSpecification lattice in lattices) { double computed = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT, vol, interest, dividend); assertEquals(computed, exact, Math.Max(exact, 1d) * tol); } } } } } } }
/// <summary> /// Price an option under the specified trinomial lattice. /// <para> /// It is assumed that the volatility, interest rate and continuous dividend rate are constant /// over the lifetime of the option. /// /// </para> /// </summary> /// <param name="function"> the option </param> /// <param name="lattice"> the lattice specification </param> /// <param name="spot"> the spot </param> /// <param name="volatility"> the volatility </param> /// <param name="interestRate"> the interest rate </param> /// <param name="dividendRate"> the dividend rate </param> /// <returns> the option price </returns> public virtual double optionPrice(OptionFunction function, LatticeSpecification lattice, double spot, double volatility, double interestRate, double dividendRate) { int nSteps = function.NumberOfSteps; double timeToExpiry = function.TimeToExpiry; double dt = timeToExpiry / (double)nSteps; double discount = Math.Exp(-interestRate * dt); DoubleArray @params = lattice.getParametersTrinomial(volatility, interestRate - dividendRate, dt); double middleFactor = @params.get(1); double downFactor = @params.get(2); double upProbability = @params.get(3); double midProbability = @params.get(4); double downProbability = @params.get(5); ArgChecker.isTrue(upProbability > 0d, "upProbability should be greater than 0"); ArgChecker.isTrue(upProbability < 1d, "upProbability should be smaller than 1"); ArgChecker.isTrue(midProbability > 0d, "midProbability should be greater than 0"); ArgChecker.isTrue(midProbability < 1d, "midProbability should be smaller than 1"); ArgChecker.isTrue(downProbability > 0d, "downProbability should be greater than 0"); DoubleArray values = function.getPayoffAtExpiryTrinomial(spot, downFactor, middleFactor); for (int i = nSteps - 1; i > -1; --i) { values = function.getNextOptionValues(discount, upProbability, midProbability, downProbability, values, spot, downFactor, middleFactor, i); } return(values.get(0)); }
/// <summary> /// Price an option under the specified trinomial tree gird. /// </summary> /// <param name="function"> the option </param> /// <param name="data"> the trinomial tree data </param> /// <returns> the option price </returns> public virtual double optionPrice(OptionFunction function, RecombiningTrinomialTreeData data) { int nSteps = data.NumberOfSteps; ArgChecker.isTrue(nSteps == function.NumberOfSteps, "mismatch in number of steps"); DoubleArray values = function.getPayoffAtExpiryTrinomial(data.getStateValueAtLayer(nSteps)); for (int i = nSteps - 1; i > -1; --i) { values = function.getNextOptionValues(data.getDiscountFactorAtLayer(i), data.getProbabilityAtLayer(i), data.getStateValueAtLayer(i), values, i); } return(values.get(0)); }
/// <summary> /// Test consistency between price methods, and Greek via finite difference. /// </summary> public virtual void test_trinomialTree() { int nSteps = 135; double dt = TIME / nSteps; LatticeSpecification lattice = new CoxRossRubinsteinLatticeSpecification(); double fdEps = 1.0e-4; foreach (bool isCall in new bool[] { true, false }) { foreach (double strike in STRIKES) { foreach (double interest in INTERESTS) { foreach (double vol in VOLS) { foreach (double dividend in DIVIDENDS) { OptionFunction function = EuropeanVanillaOptionFunction.of(strike, TIME, PutCall.ofPut(!isCall), nSteps); double[] @params = lattice.getParametersTrinomial(vol, interest - dividend, dt).toArray(); DoubleArray time = DoubleArray.of(nSteps + 1, i => dt * i); DoubleArray df = DoubleArray.of(nSteps, i => Math.Exp(-interest * dt)); double[][] stateValue = new double[nSteps + 1][]; stateValue[0] = new double[] { SPOT }; IList <DoubleMatrix> prob = new List <DoubleMatrix>(); double[] probs = new double[] { @params[5], @params[4], @params[3] }; for (int i = 0; i < nSteps; ++i) { int index = i; stateValue[i + 1] = DoubleArray.of(2 * i + 3, j => SPOT * Math.Pow(@params[2], index + 1 - j) * Math.Pow(@params[1], j)).toArray(); double[][] probMatrix = new double[2 * i + 1][]; Arrays.fill(probMatrix, probs); prob.Add(DoubleMatrix.ofUnsafe(probMatrix)); } RecombiningTrinomialTreeData treeData = RecombiningTrinomialTreeData.of(DoubleMatrix.ofUnsafe(stateValue), prob, df, time); double priceData = TRINOMIAL_TREE.optionPrice(function, treeData); double priceParams = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT, vol, interest, dividend); assertEquals(priceData, priceParams); ValueDerivatives priceDeriv = TRINOMIAL_TREE.optionPriceAdjoint(function, treeData); assertEquals(priceDeriv.Value, priceData); double priceUp = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT + fdEps, vol, interest, dividend); double priceDw = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT - fdEps, vol, interest, dividend); double fdDelta = 0.5 * (priceUp - priceDw) / fdEps; assertEquals(priceDeriv.getDerivative(0), fdDelta, 3.0e-2); } } } } } }
/// <summary> /// Compute option price and delta under the specified trinomial tree gird. /// <para> /// The delta is the first derivative of the price with respect to spot, and approximated by the data embedded in /// the trinomial tree. /// /// </para> /// </summary> /// <param name="function"> the option </param> /// <param name="data"> the trinomial tree data </param> /// <returns> the option price and spot delta </returns> public virtual ValueDerivatives optionPriceAdjoint(OptionFunction function, RecombiningTrinomialTreeData data) { int nSteps = data.NumberOfSteps; ArgChecker.isTrue(nSteps == function.NumberOfSteps, "mismatch in number of steps"); DoubleArray values = function.getPayoffAtExpiryTrinomial(data.getStateValueAtLayer(nSteps)); double delta = 0d; for (int i = nSteps - 1; i > -1; --i) { values = function.getNextOptionValues(data.getDiscountFactorAtLayer(i), data.getProbabilityAtLayer(i), data.getStateValueAtLayer(i), values, i); if (i == 1) { DoubleArray stateValue = data.getStateValueAtLayer(1); double d1 = (values.get(2) - values.get(1)) / (stateValue.get(2) - stateValue.get(1)); double d2 = (values.get(1) - values.get(0)) / (stateValue.get(1) - stateValue.get(0)); delta = 0.5 * (d1 + d2); } } return(ValueDerivatives.of(values.get(0), DoubleArray.of(delta))); }