public ElwArbReadyOrder(Account elwAccount, Account optionAccount) { try { this._elwAccount = elwAccount; this._optionAccount = optionAccount; List<double> strikes = OptionUtil.GetSortedStrikeList(CallPutFlag.Call); OptionTribe ot = null; foreach (double strike in strikes) { ot = ElwOptionUtil.GetOptionTribe(strike, CallPutFlag.Call); if (ot != null && ot.ElwInfos.Count > 0) { break; } } if (ot == null) { logger.Error("option tribe does not exist in ElwArbreadyOrder"); Util.KillWithNotice("option tribe does not exist in ElwArbreadyOrder"); } this._elwInfo = ot.ElwInfos[0]; if (this._elwInfo == null) { logger.Error("elw info does not exist in ElwArbreadyOrder"); Util.KillWithNotice("elw info does not exist in ElwArbreadyOrder"); } this._koi = ElwOptionUtil.GetKOIFromElwInfo(_elwInfo); if (this._koi == null) { logger.Error("koi info does not exist in ElwArbreadyOrder"); Util.KillWithNotice("koi info does not exist in ElwArbreadyOrder"); } this._elwLongPrice = 5; this._koiShortPrice = this._koi.UpLimit; } catch (System.Exception ex) { logger.Error(ex.ToString()); Util.KillWithNotice(ex.ToString()); } }
public static ElwOptionArbData GetElwOptionArbData( ElwInfo elw, RawMarketData rmdElw, KospiOptionInfo kospiOptionInfo, RawMarketData rmdOption, long maxCountOfOptionPerOnce, double maxValueOfOptionPerOnce, Account optionAccount, Account elwAccount, Boolean bForward, Boolean bAgressiveReverseOn, long totalAttemptOptionCount) { PreData data = GetPreData( elw, rmdElw, kospiOptionInfo, rmdOption, maxCountOfOptionPerOnce, maxValueOfOptionPerOnce, optionAccount, elwAccount, bForward, bAgressiveReverseOn, totalAttemptOptionCount); { ElwOptionArbData eoad = GetElwOptionArbData_WithProfit(data); if (eoad != null) { return eoad; } } { ElwOptionArbData eoad = GetElwOptionArbData_WO_Profit(data); if (eoad != null) { return eoad; } } return null; }
public ElwArbEach( KospiOptionInfo koi, List<ElwInfo> elwData, double strike, Account optionAccount, Account elwAccount, long maxOptionCountPerOnce, long maxOptionValuePerOnce, STR_ElwArb parent) { _KospiOptionInfo = koi; _elwData = elwData; _strike = strike; _optionAccount = optionAccount; _elwAccount = elwAccount; MaxOptionCountPerOnce = maxOptionCountPerOnce; _maxOptionValuePerOnce = maxOptionValuePerOnce; _parent = parent; Boolean bEnableReverse = true; _eaer = new ElwArbEachReverse(this, bEnableReverse); _eaecc = new ElwArbEachConditionChecker(this, _eaer, maxOptionCountPerOnce); }
void TakeOverPosition_Raw(KospiOptionInfo koi, ElwInfo elw, long optionCount, POrder optionOrder, POrder elwOrder) { ElwArbSweepUnit eos = new ElwArbSweepUnit(koi, elw, optionCount, optionOrder, elwOrder, _parent); logger.Info( "{0}\t{1}\t{2}\t ElwArbEach EOS is created...", koi.Code, elw.Code, optionCount.ToString("n0")); _lives.Add(eos); }
public ElwOptionArbData( ElwInfo elw, double elwPrice, TradingDirection elwLS, KospiOptionInfo koi, double optionPrice, TradingDirection optionLS, long minOptionCount, long diff, RawMarketData rmdOption, RawMarketData rmdElw, Boolean bForward) { OptionCode = koi.Code; ElwCode = elw.Code; OptionCount = minOptionCount; ElwCount = ElwOptionUtil.ConvertOptionCountToElwCount(elw, minOptionCount); OptionPrice = optionPrice; ElwPrice = elwPrice; Elw = elw; Diff = diff; ElwLS = elwLS; OptionLS = optionLS; IsForward = bForward; Key = String.Format("{0};{1}", koi.Code, elw.Code); RmdOption = rmdOption; RmdElw = rmdElw; }
static Boolean IsCheapEnoughPassNabiTest(Boolean bForward, KospiOptionInfo koi, RawMarketData rmdElw, ElwInfo elw, long elwBookValue) { if (bForward) { // Long하려는 ELW가 싼지 결정해야 한다. double nextStrike = OptionUtil.GetNextStrike(koi.Strike); double nextStrike2 = OptionUtil.GetNextStrike(nextStrike); double preStrike = OptionUtil.GetPreStrike(koi.Strike); double preStrike2 = OptionUtil.GetPreStrike(preStrike); DateTime maturity = Util.GetSystemOptionMaturity(); KospiOptionInfo koiNext = OptionUtil.GetKOI(nextStrike, koi.CallPut, maturity); KospiOptionInfo koiNext2 = OptionUtil.GetKOI(nextStrike2, koi.CallPut, maturity); KospiOptionInfo koiPre = OptionUtil.GetKOI(preStrike, koi.CallPut, maturity); KospiOptionInfo koiPre2 = OptionUtil.GetKOI(preStrike2, koi.CallPut, maturity); if (koiNext == null || koiNext2 == null || koiPre == null || koiPre2 == null) { return false; } RawMarketData rmdNext = RmdManager.Ins().GetData(koiNext.Code); RawMarketData rmdNext2 = RmdManager.Ins().GetData(koiNext2.Code); RawMarketData rmdPre = RmdManager.Ins().GetData(koiPre.Code); RawMarketData rmdPre2 = RmdManager.Ins().GetData(koiPre2.Code); // Cur, Next, Next2로 나비 구성해본다. 나비 구성되면 true if (Util.IsValidRMDTimeAndPrice(rmdNext) && Util.IsValidRMDTimeAndPrice(rmdNext2)) { long left = ElwOptionUtil.GetOneOptionValueOfOption(rmdNext.BidPrice1) * 2; long right = ElwOptionUtil.GetOneOptionValueOfOption(rmdNext2.AskPrice1) + elwBookValue; if (left >= right) { return true; } } if (Util.IsValidRMDTimeAndPrice(rmdPre) && Util.IsValidRMDTimeAndPrice(rmdPre2)) { long left = ElwOptionUtil.GetOneOptionValueOfOption(rmdPre.BidPrice1) * 2; long right = ElwOptionUtil.GetOneOptionValueOfOption(rmdPre2.AskPrice1) + elwBookValue; if (left >= right) { return true; } } return false; } else { // Option Long, Elw Short인 상황 double nextStrike = OptionUtil.GetNextStrike(koi.Strike); double preStrike = OptionUtil.GetPreStrike(koi.Strike); if (koi == null) { return false; } DateTime maturity = Util.GetSystemOptionMaturity(); KospiOptionInfo koiNext = OptionUtil.GetKOI(nextStrike, koi.CallPut, maturity); KospiOptionInfo koiPre = OptionUtil.GetKOI(preStrike, koi.CallPut, maturity); if (koiNext == null || koiPre == null) { return false; } RawMarketData rmdNext = RmdManager.Ins().GetData(koiNext.Code); RawMarketData rmdPre = RmdManager.Ins().GetData(koiPre.Code); if (!Util.IsValidRMDTimeAndPrice(rmdNext) || !Util.IsValidRMDTimeAndPrice(rmdPre)) { return false; } long left = elwBookValue * 2; long right = ElwOptionUtil.GetOneOptionValueOfOption(rmdPre.AskPrice1) + ElwOptionUtil.GetOneOptionValueOfOption(rmdNext.AskPrice1); // ELW를 BidPrice1으로 숏하고 양 옆의 옵션을 AskPrice1으로 롱해도 Arb이 되는 상황이다. if (left >= right) { return true; } return false; } }
static PreData GetPreData( ElwInfo elw, RawMarketData rmdElw, KospiOptionInfo kospiOptionInfo, RawMarketData rmdOption, long maxCountOfOptionPerOnce, double maxValueOfOptionPerOnce, Account optionAccount, Account elwAccount, Boolean bForward, Boolean bAgressiveReverseOn, long totalAttemptOptionCount) { PreData data = new PreData(); // 기본 input data.Elw = elw; data.RmdElw = rmdElw; data.KOI = kospiOptionInfo; data.RmdOption = rmdOption; data.MaxCountOfOptionPerOnce = maxCountOfOptionPerOnce; data.MaxValueOfOptionPerOnce = maxValueOfOptionPerOnce; data.OptionAccount = optionAccount; data.ElwAccount = elwAccount; data.IsForward = bForward; data.IsAgressiveReverseOn = bAgressiveReverseOn; data.TotalAttemptOptionCount = totalAttemptOptionCount; // 가공 데이터 data.ElwPrice = bForward ? rmdElw.AskPrice1 : rmdElw.BidPrice1; data.ElwCount = bForward ? rmdElw.AskCount1 : rmdElw.BidCount1; data.ElwLS = bForward ? TradingDirection.Long : TradingDirection.Short; data.OptionPrice = bForward ? Math.Round(rmdOption.BidPrice1, 2) : Math.Round(rmdOption.AskPrice1, 2); data.OptionCount = bForward ? rmdOption.BidCount1 : rmdOption.AskCount1; data.OptionLS = bForward ? TradingDirection.Short : TradingDirection.Long; data.OptionCountOfElw = ElwOptionUtil.ConvertElwCountToOptionCount(elw, data.ElwCount); data.ElwOneOptionValue = ElwOptionUtil.GetOneOptionValueOfElw(elw, data.ElwPrice); data.OptionOneOptionValue = ElwOptionUtil.GetOneOptionValueOfOption(data.OptionPrice); data.Diff = data.OptionOneOptionValue - data.ElwOneOptionValue; if (!bForward) { data.Diff *= (-1); // forward가 아니라면 부호를 반대로 } return data; }
public ElwArbSweepUnit( KospiOptionInfo koi, ElwInfo elwInfo, long optionCount, POrder optionOrder, POrder elwOrder, STR_ElwArb parent) { try { // 이 생성자는 인수인계를 받을 때만 사용하도록 한다. // 주의한다. _state = State._5_Done; if (optionOrder.LongShort == elwOrder.LongShort) { logger.Error("OptionOrder, ElwOrder same trading direction"); Util.KillWithNotice("OptionOrder, ElwOrder same trading direction"); throw new Exception(); } OptionAccount = null; ElwAccount = null; long elwCount = ElwOptionUtil.ConvertOptionCountToElwCount(elwInfo, optionCount); OptionOrderGoal = new POrder( TradingDirection.Short, optionOrder.Code, optionCount, optionOrder.ReqPrice, optionOrder.TargetAccount, optionOrder.RMDClone, MarketType._3_Default, true); OptionOrderGoal.AddComment("ElwOptionSweeper.TakeOver.OptionOrderGoal"); OptionOrderGoal.UpdateForRemain(OptionOrderGoal.ReqCount, OptionOrderGoal.InitReqPrice); ElwOrderGoal = new POrder( TradingDirection.Long, elwOrder.Code, elwCount, elwOrder.ReqPrice, elwOrder.TargetAccount, elwOrder.RMDClone, MarketType._3_Default, true); ElwOrderGoal.AddComment("ElwOptionSweeper.TakeOver.ElwOrderGoal"); ElwOrderGoal.UpdateForRemain(ElwOrderGoal.ReqCount, ElwOrderGoal.InitReqPrice); ElwOrdersReal = new List<POrder>(); OptionOrdersReal = new List<POrder>(); POrder elwOrderReal = new POrder(ElwOrderGoal); elwOrderReal.AddComment("ElwOptionSweeper.TakeOver.elwOrderReal"); elwOrderReal.UpdateForRemain(elwOrderReal.ReqCount, elwOrderReal.InitReqPrice); ElwOrdersReal.Add(elwOrderReal); POrder optionOrderReal = new POrder(OptionOrderGoal); optionOrderReal.AddComment("ElwOptionSweeper.TakeOver.optionOrderReal"); optionOrderReal.UpdateForRemain(optionOrderReal.ReqCount, optionOrderReal.InitReqPrice); OptionOrdersReal.Add(optionOrderReal); _parent = parent; KOI = koi; Key = String.Format("{0};{1}", OptionOrderGoal.Code, ElwOrderGoal.Code); IsBodySweepQuickly = false; } catch (System.Exception ex) { logger.Error(ex.ToString()); Util.KillWithNotice(ex.ToString()); } }
public static KospiOptionInfo GetPreKospiOptionInfo(KospiOptionInfo cur) { if (cur == null) { return null; } DateTime maturity = Util.GetSystemOptionMaturity(); double strike = GetPreStrike(cur.Strike); return OptionUtil.GetKOI(strike, cur.CallPut, maturity); }
public ElwArbSweepUnit( KospiOptionInfo koi, ElwInfo elwInfo, Account optionAccount, POrder optionOrder, Account elwAccount, POrder elwOrder, STR_ElwArb parent, DateTime dtEnd) { try { KOI = koi; CurID = ++ID_GENERATOR; OptionAccount = optionAccount; OptionOrderGoal = optionOrder; OptionOrderGoal.AddComment("EOS Constructor"); ElwAccount = elwAccount; ElwOrderGoal = elwOrder; ElwOrderGoal.AddComment("EOS Constructor"); _elwInfo = elwInfo; OptionOrdersReal = new List<POrder>(); ElwOrdersReal = new List<POrder>(); _state = State._1_MuteFewSecs; Key = String.Format("{0};{1}", OptionOrderGoal.Code, ElwOrderGoal.Code); ShowState(); _mute = new Timer(ENTER_POSITION_MUTE, ""); RequestInitOrder(ElwOrderGoal, ElwOrdersReal); _parent = parent; _parent.IncreaseEnteredArbCount(KOI.Code, OptionOrderGoal.ReqCount); _dtEnd = dtEnd; IsBodySweepQuickly = false; } catch (System.Exception ex) { logger.Error(ex.ToString()); Util.KillWithNotice(ex.ToString()); } finally { ElwAccount.DiffFastExactPossibleShortCount(ElwOrderGoal.Code, "ElwOptionSweeper 생성자"); OptionOrderGoal.Free(); optionOrder.Free(); ElwOrderGoal.Free(); elwOrder.Free(); } }
Boolean IsHighEnoughToPassNabi_Raw( KospiOptionInfo pre, KospiOptionInfo cur, KospiOptionInfo next, double fixedPrePrice, double fixedCurPrice, double fixedNextPrice) { if (pre == null || next == null || cur == null) { return false; } KospiOptionBoard board = null; if (pre.CallPut == CallPutFlag.Call) { board = RmdManager.Ins().Call; } else if (pre.CallPut == CallPutFlag.Put) { board = RmdManager.Ins().Put; } else { logger.Error("Invalid"); Util.KillWithNotice("Invalid"); } RawMarketData preRMD = board.GetData(pre.Code); RawMarketData curRMD = board.GetData(cur.Code); RawMarketData nextRMD = board.GetData(next.Code); if (!Util.IsValidRMDTimeAndPrice(preRMD) || !Util.IsValidRMDTimeAndPrice(curRMD) || !Util.IsValidRMDTimeAndPrice(nextRMD)) { return false; } double prePrice = fixedPrePrice; double curPrice = fixedCurPrice; double nextPrice = fixedNextPrice; if (!Util.IsValidPrice(prePrice)) { prePrice = preRMD.AskPrice1; } if (!Util.IsValidPrice(curPrice)) { curPrice = curRMD.BidPrice1; } if (!Util.IsValidPrice(nextPrice)) { nextPrice = nextRMD.AskPrice1; } // ELW를 BidPrice1으로 숏하고 양 옆의 옵션을 AskPrice1으로 롱해도 Arb이 되는 상황이다. if (curPrice * 2 >= prePrice + nextPrice) { return true; } return false; }
Boolean IsLowEnoughToPassNabiAsPre(KospiOptionInfo pre, double prePrice) { KospiOptionInfo cur = OptionUtil.GetNextKospiOptionInfo(pre); KospiOptionInfo next = OptionUtil.GetNextKospiOptionInfo(cur); return IsHighEnoughToPassNabi_Raw(pre, cur, next, prePrice, double.MaxValue, double.MaxValue); }
Boolean IsLowEnoughToPassNabiAsNext(KospiOptionInfo next, double nextPrice) { KospiOptionInfo cur = OptionUtil.GetPreKospiOptionInfo(next); KospiOptionInfo pre = OptionUtil.GetPreKospiOptionInfo(cur); return IsHighEnoughToPassNabi_Raw(pre, cur, next, double.MaxValue, double.MinValue, nextPrice); }
Boolean EnterNewDoorOrder(ElwInfo targetElw, KospiOptionInfo targetKOI, KospiOptionInfo doorKOI) { try { const double kDownBarrier = 0.1; const double kMinBuffer = 0.5; RawMarketData targetOptionRMD = RmdManager.Ins().GetDataClone(targetKOI.Code); RawMarketData doorOptionRMD = RmdManager.Ins().GetDataClone(doorKOI.Code); if (!Util.IsValidPrice(targetOptionRMD.BidPrice1)) { return false; } if (!Util.IsValidPrice(doorOptionRMD.BidPrice1)) { return false; } if (doorOptionRMD.BidPrice1 <= kDownBarrier) { return false; } if (targetOptionRMD.BidPrice1 <= doorOptionRMD.BidPrice1) { logger.Warn("{0} {1} <= {2} {3}", targetOptionRMD.Code, targetOptionRMD.BidPrice1, doorOptionRMD.Code, doorOptionRMD.BidPrice1); return false; } String elwCode = targetElw.Code; double reqPrice = ElwOptionUtil.ConvertOptionPriceToElwPrice(targetElw, doorOptionRMD.BidPrice1); // same strike의 bidPrice - kMinBuffer 가격에 해당하는 price double reqPrice2 = ElwOptionUtil.ConvertOptionPriceToElwPrice(targetElw, Math.Max(0, targetOptionRMD.BidPrice1 - kMinBuffer)); // reference bidPrice와 target(같은 strike의 옵션)의 bidPrice - 0.5 중에 작은 값을 take reqPrice = Math.Min(reqPrice, reqPrice2); // 5원보다 작으면 정말 이상한 것이다. if (reqPrice < 4) { return false; } long reqCount = targetElw.MaxPossibleOrderCount; if (_parent.EnterMinCount) { reqCount = 10; // 테스트 경우 무조건 10개 주문 } Account account = _parent.Parent.ElwAccount; RawMarketData rmdElw = RmdManager.Ins().GetDataClone(elwCode); POrder o = new POrder(TradingDirection.Long, elwCode, reqCount, reqPrice, account, rmdElw); OrderLimitReferenceOOR limitReference = new OrderLimitReferenceOOR(OrderLimitReferenceOOR.OrderType.OOR, targetOptionRMD); o.LimitOrderReference = limitReference; POrderUtil.RequestOrder(o, this._orders); _parent.Parent.AddFishingOrder(o, STR_Door.FishingOrderType.Active); return true; } catch (System.Exception ex) { logger.Error(ex.ToString()); Util.KillWithNotice(ex.ToString()); } return false; }
Boolean CancelDangerousOrders_Raw(POrder order, ElwInfo targetElw, KospiOptionInfo targetKOI, KospiOptionInfo doorKOI) { try { const double kBuffer = 0.3; RawMarketData targetOptionRMD = RmdManager.Ins().GetDataClone(targetKOI.Code); RawMarketData doorOptionRMD = RmdManager.Ins().GetDataClone(doorKOI.Code); Boolean bTargetRMDBidPriceValid = Util.IsValidPrice(targetOptionRMD.BidPrice1); Boolean bDoorRMDBidPriceValid = Util.IsValidPrice(doorOptionRMD.BidPrice1); if (!bTargetRMDBidPriceValid && !bDoorRMDBidPriceValid) { // 둘다 값이 없으면 위험해 보인다. 이런 경우에는 취소를 한다. return true; } if (bDoorRMDBidPriceValid) { // reference를 바로 옆 옵션으로 했다. // 바로 옆 옵션 가격보다 높은 가격으로 reqPrice했다면 위험한 상태이다. double elwPriceOfOption = ElwOptionUtil.ConvertOptionPriceToElwPrice(targetElw, doorOptionRMD.BidPrice1); if (elwPriceOfOption <= order.ReqPrice) { return true; } else { return false; } } else if (bTargetRMDBidPriceValid) { // target이 있다면 target BidPrice - kBuffer < reqPrice라면 위험한 상태이다. double elwPriceOfOption = ElwOptionUtil.ConvertOptionPriceToElwPrice(targetElw, Math.Max(0, targetOptionRMD.BidPrice1 - kBuffer)); if (elwPriceOfOption <= order.ReqPrice) { return true; } else { return false; } } else { return false; } } catch (System.Exception ex) { logger.Error(ex.ToString()); Util.KillWithNotice(ex.ToString()); } return true; }