// A - B를 진행한다.
        public static Position_KtbSkel GetForwardMinusBackward(
            Position_KtbSkel forward, Position_KtbSkel backward)
        {
            if (forward.SignedSpotCount <= 0 || backward.SignedSpotCount >= 0)
            {
                String ex = "Invalid";
                logger.Error(ex.ToString());
                Util.KillWithNotice(ex.ToString());
            }

            if (Math.Abs(forward.SignedSpotCount) <= Math.Abs(backward.SignedSpotCount))
            {
                return null;
            }

            String cSpotCode = forward.SpotCode;
            String cFutureCode = forward.FutureCode;

            double cSpotAvgPrice = forward.SpotAvgPriceTimeAdjust;
            double cFutureAvgPrice = forward.FutureAvgPrice;

            // c.SignedSpotCount이 양수라면 a > b 이었고 아직도 남아있는 것을 의미한다.
            // c.SignedSpotCount이 음수라면 a < b 이었고 지우고도 b가 남아있는 것을 의미한다.
            long cSignedSpotCount = forward.SignedSpotCount + backward.SignedSpotCount;
            long cSignedFutureCount = forward.SignedFutureCount + backward.SignedFutureCount;

            Position_KtbSkel c =
                new Position_KtbSkel(
                    cSpotCode, cSignedSpotCount, cSpotAvgPrice,
                    cFutureCode, cSignedFutureCount, cFutureAvgPrice,
                    forward.TradingDate, forward.TimeRising);

            return c;
        }
        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                long spotCount = Convert.ToInt32(textBox15.Text); // spot count
                double spotAvgPrice = Convert.ToDouble(textBox16.Text); // spot price

                double futureAvgPrice = Convert.ToDouble(textBox14.Text); // future price
                long futureCount = Convert.ToInt32(textBox13.Text); // future count

                // 포지션 등록
                Position_KtbSkel target = _parent.GetTargetPosition();

                String spotCode = target.SpotCode;
                String futureCode = target.FutureCode;

                DateTime tradingDate = CoreLib.DateUtil.GetTodayDateTime(0, 0, 0);

                Position_KtbSkel real = new Position_KtbSkel(
                    spotCode, spotCount, spotAvgPrice,
                    futureCode, futureCount, futureAvgPrice,
                    tradingDate, 0);

                _parent.SetRealPosition(real);

                this.Close();
            }
            catch (System.Exception ex)
            {
                logger.Warn(ex.ToString());
            }
        }
        public double GetOneUnitPnL(
            Position_KtbSkel position, RawMarketData spotRmdClone, RawMarketData futureRmdClone)
        {
            double spotProfit = spotRmdClone.BidPrice1 - position.SpotAvgPriceTimeAdjust;
            double futureProfit = (position.FutureAvgPrice - futureRmdClone.AskPrice1) * 100;

            double pnl = spotProfit + futureProfit;
            return pnl;
        }
 public Boolean IsExitChance(
     Position_KtbSkel position, RawMarketData spotRmdClone, RawMarketData futureRmdClone)
 {
     double pnl = GetOneUnitPnL(position, spotRmdClone, futureRmdClone);
     if (pnl >= kProfitPoint)
     {
         return true;
     }
     return false;
 }
        public void TestKtbSkelPosition()
        {
            List<Position_KtbSkel> data = new List<Position_KtbSkel>();

            // 가장 싸게 사고 비싸게 판 경우
            Position_KtbSkel datum1 = new Position_KtbSkel(
                "", 10, 8888,
                "", -10, 107.01);

            Position_KtbSkel datum2 = new Position_KtbSkel(
                "", 10, 8889,
                "", -10, 107.01);

            // 가장 비싸게 사고 싸게 판 경우
            Position_KtbSkel datum3 = new Position_KtbSkel(
                "", 10, 8889,
                "", -10, 107.00);

            data.Add(datum1);
            data.Add(datum2);
            data.Add(datum3);

            data.Sort(delegate(Position_KtbSkel mine, Position_KtbSkel other)
            {
                double mineValue = (mine.FutureAvgPrice * 100.0 - mine.SpotAvgPriceTimeAdjust);
                double otherValue = (other.FutureAvgPrice * 100.0 - other.SpotAvgPriceTimeAdjust);

                // 값 의미 0보다
                // 작음 이 개체는 other 매개 변수보다 작습니다.
                //    0 이 개체는 other와 같습니다. 0보다 큼 이 개체는 other보다 큽니다.
                if (mineValue < otherValue)
                {
                    return -1;
                }
                else if (mineValue == otherValue)
                {
                    return 0;
                }
                return 1;
            });

            Assert.AreEqual(data[0], datum3);
            Assert.AreEqual(data[1], datum2);
            Assert.AreEqual(data[2], datum1);
        }
        void TestPositionUtil_BigMinusBig()
        {
            Position_KtbSkel big1 = new Position_KtbSkel(
                "", 20, 8888,
                "", -20, 107.01);

            Position_KtbSkel big2 = new Position_KtbSkel(
                "", -20, 8887,
                "", 20, 107.00);

            Position_KtbSkel a = PositionUtil_KtbSkel.GetForwardMinusBackward(big1, big2);
            Assert.AreEqual(a, null);

            Position_KtbSkel b = PositionUtil_KtbSkel.GetBackwardMinusForward(big1, big2);
            Assert.AreEqual(b, null);
            Assert.AreEqual(PositionUtil_KtbSkel.IsZero(b), true);
        }
 public static Boolean IsZero(Position_KtbSkel pos)
 {
     if (pos == null || pos.SignedSpotCount == 0)
     {
         return true;
     }
     return false;
 }
        public static Boolean IsPlus(Position_KtbSkel pos)
        {
            if (pos == null)
            {
                return false;
            }

            if (pos.SignedSpotCount > 0)
            {
                return true;
            }
            return false;
        }
        public static PositionShareDivision_KtbSkel GetShareDivision(
            Position_KtbSkel forward, Position_KtbSkel backward)
        {
            // A가 기존에 있는 값이고 B는 Reverse를 의미한다.
            if (forward.SignedSpotCount <= 0 || backward.SignedSpotCount >= 0)
            {
                String ex = "Invalid";
                logger.Error(ex.ToString());
                Util.KillWithNotice(ex.ToString());
            }

            PositionShareDivision_KtbSkel sd = new PositionShareDivision_KtbSkel();
            sd.DivisionForward = GetForwardMinusBackward(forward, backward);
            sd.Share = GetShare(forward, backward);
            sd.DivisionBackward = GetBackwardMinusForward(forward, backward);

            if (IsZero(sd.DivisionForward) && IsZero(sd.DivisionBackward))
            {
                sd.DivisionType = PositionShareDivision_KtbSkel.ForwardBackwardDivisionType.RemainEmpty;
            }

            if (sd.DivisionForward != null &&
                sd.DivisionBackward != null)
            {
                String ex = "Invalid";
                logger.Error(ex.ToString());
                Util.KillWithNotice(ex.ToString());
            }

            if (sd.DivisionForward != null)
            {
                sd.DivisionType = PositionShareDivision_KtbSkel.ForwardBackwardDivisionType.ForwardRemained;
            }

            if (sd.DivisionBackward != null)
            {
                sd.DivisionType = PositionShareDivision_KtbSkel.ForwardBackwardDivisionType.BackwardRemained;
            }
            return sd;
        }
        public static DonePosition_KtbSkel GetShare(Position_KtbSkel forward, Position_KtbSkel backward)
        {
            long spotUnsignedCount = Math.Min(
                Math.Abs(forward.SignedSpotCount),
                Math.Abs(backward.SignedSpotCount));

            long futureUnsignedCount = Math.Min(
                Math.Abs(forward.SignedFutureCount),
                Math.Abs(backward.SignedFutureCount));

            DonePosition_KtbSkel ret = new DonePosition_KtbSkel(
                forward.SpotCode, spotUnsignedCount, forward.SpotAvgPriceTimeAdjust, backward.SpotAvgPriceTimeAdjust,
                forward.FutureCode, futureUnsignedCount, forward.FutureAvgPrice, backward.FutureAvgPrice);

            return ret;
        }
        public void Push(Position_KtbSkel position)
        {
            if (PositionUtil_KtbSkel.IsZero(position))
            {
                return;
            }

            CheckValidData(position, true);

            _stack.Add(position);

            SortStack();
        }
        void TestTakeOverPosition()
        {
            string strategyName = "unittest_position";
            long maxNotional = 100;
            double downBoundary = 0F;
            double upBoundary = 10F;

            StrategyManager.Ins().UnRegister(strategyName);
            AgentManager.Ins().Clear();

            STR_KtbSkel factory = new STR_KtbSkel();
            Input_KtbSkel input = new Input_KtbSkel();
            input.MaxNotional = maxNotional;
            input.Spot10yrCode = "KR1035027161";
            input.Future10yrCode = "167FC000";

            Serializer serializer = new Serializer(typeof(Input_KtbSkel));
            String jsonText = serializer.Serialize(input);

            STR_KtbSkel strategy = StrategyBuilder_KtbSkel.CreateStrategy(jsonText, strategyName);
            PrivateObject po = new PrivateObject(strategy);
            STR_KtbSkel_Accessor strategyAcc = new STR_KtbSkel_Accessor(po);
            strategyAcc.SetAccountOrderLimit();

            ProcessController_KtbSkel controller = strategyAcc.Controller;

            String spotCode = KtbSpotUtil.Ins().KtbSpot_10yr.Code;
            String futureCode = KtbFutureUtil.Ins().KtbFuture_10yr_1.Code;

            SortedPositionStack_KtbSkel target =
                new SortedPositionStack_KtbSkel(controller, strategyName, spotCode, futureCode,
                    maxNotional, downBoundary, upBoundary);

            SortedPositionStack_KtbSkel_Accessor acc =
                new SortedPositionStack_KtbSkel_Accessor(
                    new PrivateObject(target));

            acc._stack.Clear();
            acc.DeleteTable();

            int i = 1;
            Position_KtbSkel pos1 = new Position_KtbSkel(
                spotCode, 50 * i, 8888,
                futureCode, (-50) * i, 107.00);
            ++i;
            Position_KtbSkel pos2 = new Position_KtbSkel(
                spotCode, 50 * i, 8888,
                futureCode, (-50) * i, 107.04);
            ++i;
            Position_KtbSkel pos3 = new Position_KtbSkel(
                spotCode, 50 * i, 8888,
                futureCode, (-50) * i, 107.02);
            ++i;
            Position_KtbSkel pos4 = new Position_KtbSkel(
                spotCode, 50 * i, 8888,
                futureCode, (-50) * i, 107.03);

            acc.Push(pos1);
            acc.ToDB();
            acc._stack.Clear();
            acc.TakeOverPositionFromDB();

            Assert.AreEqual(1, acc._stack.Count);

            acc.DeleteTable();
            acc._stack.Clear();

            acc.Push(pos1);
            acc.Push(pos2);
            acc.Push(pos3);
            acc.Push(pos4);
            acc.ToDB();
            acc._stack.Clear();
            Assert.AreEqual(0, acc._stack.Count);

            acc.TakeOverPositionFromDB();
            Assert.AreEqual(4, acc._stack.Count);
            Assert.AreEqual(acc.Peek().SignedSpotCount, 100);
        }
        // 포지션을 꺾을 때의 손익이다.
        public static double GetPnLIfExit(Position_KtbSkel pos)
        {
            RawMarketData rmdSpot = RmdManager.Ins().GetData(pos.SpotCode);
            RawMarketData rmdFuture = RmdManager.Ins().GetData(pos.FutureCode);
            double spotOutPrice = rmdSpot.BidPrice1;
            double futureOutPrice = rmdFuture.AskPrice1;

            double spotInPrice = pos.SpotAvgPriceTimeAdjust;
            double futureInPrice = pos.FutureAvgPrice;

            long spotUnsignedCount = Math.Abs(pos.SignedSpotCount);
            long futureUnsignedCount = Math.Abs(pos.SignedFutureCount);

            double spotPnL =
                (spotOutPrice - spotInPrice) * (double)spotUnsignedCount * CommonConst._10_000;

            double futureOnePointAmount = ProductUtil.Ins().GetOnePointAmount(pos.FutureCode);
            double futurePnL =
                (futureInPrice - futureOutPrice) * (double)futureUnsignedCount * futureOnePointAmount;

            return spotPnL + futurePnL;
        }
        public void Erase(Position_KtbSkel backward)
        {
            if (KtbSpotUtil.Ins().IsDirtyNotional(backward.SignedSpotCount))
            {
                String ex = "Dirty notional";
                logger.Error(ex.ToString());
                Util.KillWithNotice(ex.ToString());
            }

            CheckValidData(backward, false);

            while (true)
            {
                if (PositionUtil_KtbSkel.IsZero(backward))
                {
                    break;
                }

                Position_KtbSkel top = Peek();
                if (top == null)
                {
                    String ex = "Invalid";
                    logger.Error(ex.ToString());
                    Util.KillWithNotice(ex.ToString());
                    break;
                }

                PositionShareDivision_KtbSkel sd = PositionUtil_KtbSkel.GetShareDivision(top, backward);
                backward = sd.DivisionBackward;

                if (sd.Share != null)
                {
                    _donePositions.Add(sd.Share);
                }

                switch (sd.DivisionType)
                {
                    case PositionShareDivision_KtbSkel.ForwardBackwardDivisionType.ForwardRemained:
                        {
                            // 양수, top > reversePosition
                            Position_KtbSkel remainTop = sd.DivisionForward;
                            Pop();
                            Push(remainTop);
                            break;
                        }
                    case PositionShareDivision_KtbSkel.ForwardBackwardDivisionType.RemainEmpty:
                        {
                            // 지우고 끝
                            Pop();
                            break;
                        }
                    case PositionShareDivision_KtbSkel.ForwardBackwardDivisionType.BackwardRemained:
                        {
                            // 지우고 또 지운다.
                            Pop();
                            break;
                        }
                    default:
                        String ex = "여기에 오면 안된다.";
                        logger.Error(ex.ToString());
                        Util.KillWithNotice(ex.ToString());
                        break;
                }
            }
        }
 Boolean IsEmpty(Position_KtbSkel pos)
 {
     if (pos.SignedSpotCount == 0 && pos.SignedFutureCount == 0)
     {
         return true;
     }
     return false;
 }
        void InsertToDB_Raw(Position_KtbSkel pos)
        {
            String queryTemplate = "insert into ktb_skel_position " +
                "(strategy_name, spot_code, spot_count, spot_avg_price, " +
                "future_code, future_count, future_avg_price, trading_date) values " +
                "('{0}', '{1}', {2}, {3}, '{4}', {5}, {6}, '{7}')";

            String query = String.Format(
                queryTemplate,
                StrategyName,
                pos.SpotCode, pos.SignedSpotCount, pos.SpotAvgPriceTimeAdjust - pos.TimeRising,
                pos.FutureCode, pos.SignedFutureCount, pos.FutureAvgPrice,
                pos.TradingDate.ToString("yyyy-MM-dd"));

            int ret = DBUtil.Execute(query, CommonConst.DATABASE_MADVIPER);
            if (ret != 1)
            {
                logger.Warn("Delete query error. Insert fail");
            }
        }
        void CheckValidData(Position_KtbSkel position, Boolean bForward)
        {
            String ex = "Invalid Data";
            if (position.SpotCode.CompareTo(this.SpotCode) != 0)
            {
                logger.Error(ex.ToString());
                Util.KillWithNotice(ex.ToString());
            }

            if (position.FutureCode.CompareTo(this.FutureCode) != 0)
            {
                logger.Error(ex.ToString());
                Util.KillWithNotice(ex.ToString());
            }

            if (bForward)
            {
                if (position.SignedSpotCount < 0 || position.SignedFutureCount > 0)
                {
                    logger.Error(ex.ToString());
                    Util.KillWithNotice(ex.ToString());
                }
            }
            else
            {
                if (position.SignedSpotCount > 0 || position.SignedFutureCount < 0)
                {
                    logger.Error(ex.ToString());
                    Util.KillWithNotice(ex.ToString());
                }
            }
        }
        public Boolean TakeOverPositionFromDB()
        {
            String query = String.Format(
                "select * from ktb_skel_position where strategy_name = '{0}'",
                this.StrategyName);

            DataRowCollection rows = DBUtil.SelectFromDB(query, CommonConst.DATABASE_MADVIPER);

            long notionalTotal = 0;

            for (int i = 0; i < rows.Count; ++i)
            {
                DataRow row = rows[i];
                String spotCode = Convert.ToString(row["spot_code"]);
                long spotCount = Convert.ToInt64(row["spot_count"]);
                double spotAvgPrice = Convert.ToDouble(row["spot_avg_price"]);

                String futureCode = Convert.ToString(row["future_code"]);
                long futureCount = Convert.ToInt64(row["future_count"]);
                double futureAvgPrice = Convert.ToDouble(row["future_avg_price"]);
                DateTime tradingDate = Convert.ToDateTime(row["trading_date"]);

                if (spotCount <= 0)
                {
                    String ex = "국채현물 수량 이상.";
                    logger.Error(ex.ToString());
                    Util.KillWithNotice(ex.ToString());
                }

                long timeRising = (DateTime.Now - tradingDate).Days;

                spotAvgPrice += timeRising;

                Position_KtbSkel pos = new Position_KtbSkel(
                    spotCode, spotCount, spotAvgPrice,
                    futureCode, futureCount, futureAvgPrice,
                    tradingDate, timeRising);

                double reqPrice = KtbSpotUtil.Ins().RoundProductPrice(spotAvgPrice);

                RawMarketData rmd = RmdManager.Ins().KtbSpot.GetData(spotCode);
                RawMarketData rmdClone = rmd.Clone() as RawMarketData;

                Push(pos);

                notionalTotal += spotCount;
            }

            if (notionalTotal <= this.MaxNotional)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
 void TestErase_Raw(SortedPositionStack_KtbSkel_Accessor acc)
 {
     Assert.AreEqual(acc._stack.Count, 3);
     {
         // 3억에서 1억만 지운다.
         Position_KtbSkel erase = new Position_KtbSkel(
             "", -10, 8899,
             "", 10, 107.0);
         acc.Erase(erase);
         CheckRateAndNotional(acc, 0, 0, 0, 50);
     }
     Assert.AreEqual(acc._stack.Count, 3);
     {
         // 3억을 지운다.
         Position_KtbSkel erase = new Position_KtbSkel(
             "", -30, 8899,
             "", 30, 107.0);
         acc.Erase(erase);
         CheckRateAndNotional(acc, 0, 0, 0, 20);
     }
     Assert.AreEqual(acc._stack.Count, 2);
     {
         // 1억을 지운다.
         Position_KtbSkel erase = new Position_KtbSkel(
             "", -10, 8899,
             "", 10, 107.0);
         acc.Erase(erase);
         CheckRateAndNotional(acc, 0, 0, 0, 10);
     }
     Assert.AreEqual(acc._stack.Count, 1);
 }
        void TestPositionUtil_BigMinusSmall()
        {
            Position_KtbSkel forward = new Position_KtbSkel(
                "", 20, 8888,
                "", -20, 107.01);

            Position_KtbSkel small = new Position_KtbSkel(
                "", -10, 8887,
                "", 10, 107.00);

            Position_KtbSkel big = new Position_KtbSkel(
                "", -30, 8886,
                "", 30, 106.99);

            Position_KtbSkel a = PositionUtil_KtbSkel.GetForwardMinusBackward(forward, small);
            Assert.AreEqual(a.SpotAvgPriceTimeAdjust, forward.SpotAvgPriceTimeAdjust);
            Assert.AreEqual(a.FutureAvgPrice, forward.FutureAvgPrice);
            Assert.AreEqual(a.SignedSpotCount, 10);
            Assert.AreEqual(a.SignedFutureCount, -10);

            Position_KtbSkel b = PositionUtil_KtbSkel.GetBackwardMinusForward(forward, big);
            Assert.AreEqual(b.SpotAvgPriceTimeAdjust, big.SpotAvgPriceTimeAdjust);
            Assert.AreEqual(b.FutureAvgPrice, big.FutureAvgPrice);
            Assert.AreEqual(b.SignedSpotCount, -10);
            Assert.AreEqual(b.SignedFutureCount, 10);

            Assert.AreEqual(PositionUtil_KtbSkel.IsPlus(a), true);
            Assert.AreEqual(PositionUtil_KtbSkel.IsPlus(b), false);
            Assert.AreEqual(PositionUtil_KtbSkel.IsZero(b), false);
        }
        public void TestSortedPositionStack_KtbSkel()
        {
            long maxNotional = 100;
            double downBoundary = 0F;
            double upBoundary = 10F;

            String spotCode = KtbSpotUtil.Ins().KtbSpot_10yr.Code;
            String futureCode = KtbFutureUtil.Ins().KtbFuture_10yr_1.Code;

            SortedPositionStack_KtbSkel target = new SortedPositionStack_KtbSkel(null, "unittest", spotCode, futureCode,
                maxNotional, downBoundary, upBoundary);

            Assert.AreEqual(target.MaxNotional, maxNotional);
            Assert.AreEqual(target.DownBoundary, downBoundary);
            Assert.AreEqual(target.UpBoundary, upBoundary);

            SortedPositionStack_KtbSkel_Accessor acc = new SortedPositionStack_KtbSkel_Accessor(
                new PrivateObject(target));

            // 미만
            CheckRateAndNotional(acc, -0.1F, 0.0F, 0, 0);
            CheckRateAndNotional(acc, -10.0F, 0.0F, 0, 0);

            // 정상상태
            CheckRateAndNotional(acc, 0.0F, 0.0F, 0, 0);
            CheckRateAndNotional(acc, 1.0F, 0.1F, (long)(maxNotional * 0.1), 0);
            CheckRateAndNotional(acc, 3.0F, 0.3F, (long)(maxNotional * 0.3), 0);
            CheckRateAndNotional(acc, 10.0F, 1.0F, maxNotional, 0);

            // 오버
            CheckRateAndNotional(acc, 11.0F, 1.0F, maxNotional, 0);
            CheckRateAndNotional(acc, 100.0F, 1.0F, maxNotional, 0);

            CheckRateAndNotional(acc, 0.1F, 0.01F, 0, 0);
            CheckRateAndNotional(acc, 0.25F, 0.025F, 0, 0);

            //push pos1
            Position_KtbSkel pos1 = new Position_KtbSkel(
                spotCode, 10, 8889,
                futureCode, -10, 107.00);

            acc.Push(pos1);
            CheckRateAndNotional(acc, 0, 0, 0, 10);

            //push pos2
            Position_KtbSkel pos2 = new Position_KtbSkel(
                spotCode, 20, 8888,
                futureCode, -20, 107.00);
            acc.Push(pos2);
            CheckRateAndNotional(acc, 0, 0, 0, 30);

            //push pos3
            Position_KtbSkel pos3 = new Position_KtbSkel(
                spotCode, 30, 8887,
                futureCode, -30, 107.10);
            acc.Push(pos3); // pos3가 top
            CheckRateAndNotional(acc, 0, 0, 0, 60);

            TestErase_Raw(acc);

            TestReverseSweeperAfterTakeOverPosition();
        }
        void TestPositionUtil_SmallMinusBig()
        {
            Position_KtbSkel small = new Position_KtbSkel(
                "", 10, 8888,
                "", -10, 107.01);

            Position_KtbSkel big = new Position_KtbSkel(
                "", -20, 8887,
                "", 20, 107.00);

            Position_KtbSkel a = PositionUtil_KtbSkel.GetForwardMinusBackward(small, big);
            Assert.AreEqual(a, null);

            Position_KtbSkel b = PositionUtil_KtbSkel.GetBackwardMinusForward(small, big);
            Assert.AreEqual(b.SpotAvgPriceTimeAdjust, big.SpotAvgPriceTimeAdjust);
            Assert.AreEqual(b.FutureAvgPrice, big.FutureAvgPrice);
            Assert.AreEqual(b.SignedSpotCount, -10);
            Assert.AreEqual(b.SignedFutureCount, 10);

            Assert.AreEqual(PositionUtil_KtbSkel.IsPlus(b), false);
            Assert.AreEqual(PositionUtil_KtbSkel.IsZero(b), false);
        }