public List <decimal[]> Estimate_Matrix_Profit(AppTypes.TimeRanges timeRange, string timeScaleCode, string[] stockCodeList, string[] strategyList, EstimateOptions option) { return(application.Strategy.Libs.Estimate_Matrix_Profit(timeRange, AppTypes.TimeScaleFromCode(timeScaleCode), common.system.List2Collection(stockCodeList), common.system.List2Collection(strategyList), option)); }
private void DoBackTesting() { this.ShowReccount(""); this.myValueType = ValueTypes.Amount; this.Amount2PercentDenominator = Settings.sysStockTotalCapAmt; StringCollection strategyList = strategyClb.myCheckedValues; StringCollection stockCodeList = codeSelectLb.myValues; //Analysis cached data so we MUST reset to clear cache to ensure the system run correctly DataAccess.Libs.ClearCache(); EstimateOptions estimateOption = new EstimateOptions(); DataTable retsultTbl = CreateEstimateTbl(strategyList); SetDataGrid(resultDataGrid, retsultTbl); progressBar.Value = 0; progressBar.Minimum = 0; progressBar.Maximum = stockCodeList.Count; AppTypes.TimeRanges timeRange = periodicityEd.myTimeRange; string timeScaleCode = periodicityEd.myTimeScale.Code; string[] strategy = common.system.Collection2List(strategyList); this.ShowReccount(progressBar.Value.ToString() + "/" + progressBar.Maximum.ToString()); int codeStartIdx = 0, codeEndIdx = 0; while (codeStartIdx < stockCodeList.Count) { codeEndIdx += Settings.sysNumberOfItemsInBatchProcess; if (codeEndIdx >= stockCodeList.Count) { codeEndIdx = stockCodeList.Count - 1; } string[] stocks = common.system.Collection2List(stockCodeList, codeStartIdx, codeEndIdx); decimal[][] retList = DataAccess.Libs.Estimate_Matrix_Profit(timeRange, timeScaleCode, stocks, strategy, estimateOption); for (int idx = 0; idx < retList.Length; idx++) { DataRow row = retsultTbl.Rows.Add(stockCodeList[idx + codeStartIdx]); for (int colId = 0; colId < retList[idx].Length; colId++) { row[colId + 1] = retList[idx][colId]; } } Application.DoEvents(); codeStartIdx = codeEndIdx + 1; progressBar.Value = codeEndIdx + 1; this.ShowReccount(progressBar.Value.ToString() + "/" + progressBar.Maximum.ToString()); } common.system.RemoveEmptyItems(retsultTbl); SetDataGrid(resultDataGrid, retsultTbl); SetEstimateDataGrid(application.Strategy.Libs.GetStrategyStats(retsultTbl)); }
private void DoRankingDB() { this.myValueType = ValueTypes.Amount; this.Amount2PercentDenominator = Settings.sysStockTotalCapAmt; resultTab.TabPages.Clear(); StringCollection stockCodeList = codeListLb.myValues; StringCollection timeRangeList = timeRangeLb.myCheckedValues; string[] strategyList = common.system.Collection2List(strategyClb.myCheckedValues); progressBar.Value = 0; progressBar.Minimum = 0; progressBar.Maximum = stockCodeList.Count * timeRangeList.Count; EstimateOptions estimateOption = new EstimateOptions(); for (int stockCodeId = 0; stockCodeId < stockCodeList.Count; stockCodeId++) { string stockCode = stockCodeList[stockCodeId].ToString(); DataTable testRetsultTbl = CreateDataTable(timeRangeList, strategyList); common.controls.baseDataGridView resultGrid = CreateResultGrid(stockCode, testRetsultTbl); for (int colId = 0; colId < timeRangeList.Count; colId++) { try { progressBar.Value++; Application.DoEvents(); this.ShowReccount(progressBar.Value.ToString() + "/" + progressBar.Maximum.ToString()); AppTypes.TimeRanges timeRange = AppTypes.TimeRangeFromCode(timeRangeList[colId]); application.AnalysisData analysisData = new application.AnalysisData(timeRange, timeScaleCb.myValue, stockCode, commonClass.DataAccessMode.WebService); for (int rowId = 0; rowId < strategyList.Length; rowId++) { testRetsultTbl.Rows[rowId][colId + 1] = 0; //Analysis cached data so we MUST clear cache to ensure the system run correctly application.Strategy.Data.ClearCache(); application.Strategy.Data.TradePoints advices = application.Strategy.Libs.Analysis(analysisData, strategyList[rowId]); if (advices != null) { testRetsultTbl.Rows[rowId][colId + 1] = application.Strategy.Libs.EstimateTrading_Profit(analysisData, application.Strategy.Libs.ToTradePointInfo(advices), estimateOption); } } } catch (Exception er) { this.WriteError(stockCodeList[stockCodeId] + " : " + timeRangeList[colId] + " : " + strategyList[colId], er.Message); //this.ShowError(er); } } } }
private void DoBackTestUseDB() { this.myValueType = ValueTypes.Amount; this.Amount2PercentDenominator = Settings.sysStockTotalCapAmt; StringCollection strategyList = strategyClb.myCheckedValues; StringCollection stockCodeList = codeSelectLb.myValues; DataTable testRetsultTbl = CreateEstimateTbl(strategyList); SetDataGrid(resultDataGrid, testRetsultTbl); progressBar.Value = 0; progressBar.Minimum = 0; progressBar.Maximum = stockCodeList.Count; EstimateOptions estOptions = new EstimateOptions(); for (int rowId = 0; rowId < stockCodeList.Count; rowId++) { application.AnalysisData analysisData = new application.AnalysisData(periodicityEd.myTimeRange, periodicityEd.myTimeScale, stockCodeList[rowId], commonClass.DataAccessMode.WebService); DataRow row = testRetsultTbl.Rows.Add(stockCodeList[rowId]); for (int colId = 0; colId < strategyList.Count; colId++) { try { //Analysis cached data so we MUST clear cache to ensure the system run correctly application.Strategy.Data.ClearCache(); application.Strategy.Data.TradePoints advices = application.Strategy.Libs.Analysis(analysisData, strategyList[colId]); if (advices != null) { row[colId + 1] = application.Strategy.Libs.EstimateTrading_Profit(analysisData, application.Strategy.Libs.ToTradePointInfo(advices), estOptions); } else { row[colId + 1] = 0; } } catch (Exception er) { this.WriteError(stockCodeList[rowId] + " : " + strategyList[colId], er.Message); this.ShowError(er); } } progressBar.Value++; this.ShowReccount(progressBar.Value.ToString() + "/" + progressBar.Maximum.ToString()); Application.DoEvents(); } SetEstimateDataGrid(application.Strategy.Libs.GetStrategyStats(testRetsultTbl)); }
public void PlotStrategyTradepoints(application.Strategy.Meta meta, bool showEstimation) { ShowMessage(""); EstimateOptions estOption = new EstimateOptions(); data.tmpDS.tradeEstimateDataTable tbl = new data.tmpDS.tradeEstimateDataTable(); TradePointInfo[] tradePoints = DataAccess.Libs.GetTradePointWithEstimationDetail(myData.DataTimeRange, myData.DataTimeScale.Code, myData.DataStockCode, meta.Code, estOption, out tbl); /// Estimate trade points and set tradepoint's [isValid] property to mark whether a tradepoint is valid or not. for (int idx = 0; idx < tradePoints.Length; idx++) { tradePoints[idx].isValid = !tbl[idx].ignored; } PlotStrategyTradepoints(application.Strategy.Libs.ToTradePoints(tradePoints), pricePanel); //Call estimation handler if any. if (showEstimation && myEstimateTradePoints != null) { myEstimateTradePoints(this, meta.Code, estOption, tbl); } }
public TradePointInfo[] GetTradePointWithEstimationDetail(AppTypes.TimeRanges timeRange, string timeScaleCode, string stockCode, string strategyCode, EstimateOptions options, out data.tmpDS.tradeEstimateDataTable toTbl) { string dataKey = LoadAnalysisData(timeRange, timeScaleCode, stockCode, false); TradePointInfo[] tradePoints = Analysis(dataKey, strategyCode); toTbl = application.Strategy.Libs.EstimateTrading_Details(sysDataCache.Find(dataKey) as AnalysisData, tradePoints, options); return(tradePoints); }
public static TradePointInfo[] GetTradePointWithEstimationDetail(AppTypes.TimeRanges timeRange, string timeScaleCode, string stockCode, string strategyCode, EstimateOptions options, out data.tmpDS.tradeEstimateDataTable toTbl) { return(myClient.GetTradePointWithEstimationDetail(out toTbl, timeRange, timeScaleCode, stockCode, strategyCode, options)); }
public static decimal[][] Estimate_Matrix_Profit(AppTypes.TimeRanges timeRange, string timeScaleCode, string[] stocks, string[] strategyList, EstimateOptions option) { return(myClient.Estimate_Matrix_Profit(timeRange, timeScaleCode, stocks, strategyList, option)); }
public Estimate GetEstimate(Service service, int unitCount, EstimateOptions options) { throw new NotImplementedException(); }
public static List <decimal[]> Estimate_Matrix_Profit(AppTypes.TimeRanges timeRange, AppTypes.TimeScale timeScale, StringCollection stockCodeList, StringCollection strategyList, EstimateOptions option) { List <decimal[]> retList = new List <decimal[]>(); for (int rowId = 0; rowId < stockCodeList.Count; rowId++) { Data.ClearCache(); AnalysisData analysisData = new AnalysisData(timeRange, timeScale, stockCodeList[rowId], DataAccessMode.Local); decimal[] rowRetList = new decimal[strategyList.Count]; for (int colId = 0; colId < strategyList.Count; colId++) { Data.TradePoints advices = Analysis(analysisData, strategyList[colId]); if (advices != null) { rowRetList[colId] = EstimateTrading_Profit(analysisData, ToTradePointInfo(advices), option); } else { rowRetList[colId] = 0; } } retList.Add(rowRetList); } return(retList); }
/// <summary> /// Get the estimation detail from adviced trade point /// </summary> /// <param name="data"></param> /// <param name="tradePoints"></param> /// <param name="options"></param> /// <param name="toTbl"> Table of assumed transactions. Each row procides detail information of a transcation and it's profit</param> public static data.tmpDS.tradeEstimateDataTable EstimateTrading_Details(AnalysisData data, TradePointInfo[] tradePoints, EstimateOptions options) { data.tmpDS.tradeEstimateDataTable toTbl = new data.tmpDS.tradeEstimateDataTable(); EstimateTrading(data, tradePoints, options, toTbl, AfterEachEstimation_AddToTable, null); return(toTbl); }
/// <summary> /// Get estimated profit from adviced trade point /// </summary> /// <param name="data"></param> /// <param name="tradePoints"></param> /// <param name="options"></param> /// <returns></returns> public static decimal EstimateTrading_Profit(AnalysisData data, TradePointInfo[] tradePoints, EstimateOptions options) { EstimateSum myEstimateSum = new EstimateSum(); EstimateTrading(data, tradePoints, options, myEstimateSum, null, AfterEstimation_GetProfit); return(myEstimateSum.total); }
/// <summary> /// Estimate the profit from advices produced by analysis process. /// The function will produce a list of "transactions" assuming to be done from analysis advices. /// </summary> /// <param name="data"> Data used for analysis </param> /// <param name="tradePoints">Trade point list generated by analysis process</param> /// <param name="options">User- specific options : captital, max Buy...</param> /// <param name="returnObj">Returned object </param> /// <param name="afterEachEstimationFunc">Call-back function at the end of each tradepoind estimation</param> /// <param name="afterEstimationFunc">Call-back function at the end of estimation process</param> /// public static void EstimateTrading(AnalysisData data, TradePointInfo[] tradePoints, EstimateOptions options, object returnObj, AfterEachEstimationFunc afterEachEstimationFunc, AfterEstimationFunc afterEstimationFunc) { EstimationData myEstimationData = new EstimationData(); global::data.baseDS.stockExchangeRow marketRow = application.AppLibs.GetStockExchange(data.DataStockCode); decimal initCapAmt = options.TotalCapAmt * options.MaxBuyAmtPerc / 100; decimal priceWeight = marketRow.priceRatio; decimal feePerc = marketRow.tranFeePerc / 100; short buy2SellInterval = marketRow.minBuySellDay; data.baseDS.stockCodeRow stockCodeRow = application.SysLibs.FindAndCache_StockCode(data.DataStockCode); if (stockCodeRow == null) { return; } int adviceDataIdx, lastBuyId = -1; decimal stockQty = 0, qty; decimal maxBuyQty = (decimal)(stockCodeRow.noOutstandingStock * options.MaxBuyQtyPerc / 100); decimal stockAmt = 0, stockPrice = 0, amt, feeAmt, totalFeeAmt = 0; decimal cashAmt = initCapAmt; DateTime transDate = common.Consts.constNullDate;; for (int idx = 0; idx < tradePoints.Length; idx++) { adviceDataIdx = tradePoints[idx].DataIdx; qty = 0; amt = 0; myEstimationData.ignored = false; AppTypes.TradeActions action = tradePoints[idx].TradeAction; stockPrice = (decimal)data.Close[adviceDataIdx]; transDate = DateTime.FromOADate(data.DateTime[adviceDataIdx]); switch (action) { case AppTypes.TradeActions.Buy: //Assume that we can only buy if we have money qty = (stockPrice == 0 ? 0 : Math.Floor(cashAmt / ((stockPrice * priceWeight) * (1 + feePerc)))); if (qty > maxBuyQty) { qty = maxBuyQty; } if (qty != 0) { amt = qty * stockPrice * priceWeight; stockAmt += amt; stockQty += qty; feeAmt = Math.Round(amt * feePerc, 0); cashAmt -= amt + feeAmt; totalFeeAmt += feeAmt; lastBuyId = adviceDataIdx; } else { myEstimationData.ignored = true; } break; case AppTypes.TradeActions.Sell: //Can sell if own some stock if (stockQty <= 0) { myEstimationData.ignored = true; break; } // Not applicable to sell if (lastBuyId < 0) { myEstimationData.ignored = true; break; } // T+4 contrainst ? if (common.dateTimeLibs.DateDiffInDays(DateTime.FromOADate(data.DateTime[lastBuyId]).Date, DateTime.FromOADate(data.DateTime[adviceDataIdx]).Date) < buy2SellInterval) { // Keep inapplicable Sells ?? if (commonClass.Settings.sysKeepInApplicableSell) { int transDataIdx = -1; DateTime minAllowSellDate = DateTime.FromOADate(data.DateTime[lastBuyId]).Date.AddDays(buy2SellInterval); //If it is the last trade point, find the next applicable date if (idx >= tradePoints.Length - 1) { transDataIdx = FindDateIdx(data, tradePoints[idx].DataIdx + 1, data.DateTime.Count - 1, minAllowSellDate); } else { //If the next trade point is before or at [minAllowSellDate], ignore this if (DateTime.FromOADate(data.DateTime.Values[tradePoints[idx + 1].DataIdx]).Date <= minAllowSellDate) { myEstimationData.ignored = true; } else { //Find the next applicable date after this point and before next point transDataIdx = FindDateIdx(data, tradePoints[idx].DataIdx + 1, tradePoints[idx + 1].DataIdx - 1, minAllowSellDate); } } if (transDataIdx < 0) { myEstimationData.ignored = true; } else { stockPrice = (decimal)data.Close[transDataIdx]; transDate = DateTime.FromOADate(data.DateTime[transDataIdx]).Date; } } else { myEstimationData.ignored = true; } } //Ok, sell it if (!myEstimationData.ignored) { qty = stockQty; amt = qty * stockPrice * priceWeight; stockQty = 0; stockAmt = 0; feeAmt = Math.Round(amt * feePerc, 0); cashAmt += amt - feeAmt; totalFeeAmt += feeAmt; } break; } myEstimationData.tradeAction = action.ToString(); myEstimationData.onDate = transDate; myEstimationData.price = stockPrice; myEstimationData.qty = qty; myEstimationData.amt = amt; myEstimationData.feeAmt = totalFeeAmt; myEstimationData.ownedQty = stockQty; myEstimationData.ownedAmt = stockAmt; myEstimationData.cashAmt = cashAmt; myEstimationData.profitAmt = cashAmt + stockAmt - initCapAmt; if (afterEachEstimationFunc != null) { afterEachEstimationFunc(myEstimationData, returnObj); } } if (afterEstimationFunc != null) { afterEstimationFunc(myEstimationData, returnObj); } }
/// <summary> /// Thuc hien viec sap xep chien luoc /// </summary> private void DoRanking() { this.ShowReccount(""); this.myValueType = ValueTypes.Amount; this.Amount2PercentDenominator = Settings.sysStockTotalCapAmt; resultTab.TabPages.Clear(); StringCollection stockCodeList = codeListLb.myValues; StringCollection timeRangeList = timeRangeLb.myCheckedValues; string[] strategyList = common.system.Collection2List(strategyClb.myCheckedValues); progressBar.Value = 0; progressBar.Minimum = 0; progressBar.Maximum = stockCodeList.Count; string timeScaleCode = timeScaleCb.myValue.Code; EstimateOptions estimateOption = new EstimateOptions(); DataAccess.Libs.ClearCache(); ArrayList resulTblList = new ArrayList(); this.ShowReccount(progressBar.Value.ToString() + "/" + progressBar.Maximum.ToString()); int codeStartIdx = 0, codeEndIdx = 0; while (codeStartIdx < stockCodeList.Count) { codeEndIdx += Settings.sysNumberOfItemsInBatchProcess; if (codeEndIdx >= stockCodeList.Count) { codeEndIdx = stockCodeList.Count - 1; } //Create Tab and grid for each code resulTblList.Clear(); string[] processCodeList = new string[codeEndIdx - codeStartIdx + 1]; for (int idx1 = codeStartIdx, idx2 = 0; idx1 <= codeEndIdx; idx1++, idx2++) { resulTblList.Add(CreateDataTable(timeRangeList, strategyList)); CreateResultGrid(stockCodeList[idx1], resulTblList[idx2] as DataTable); processCodeList[idx2] = stockCodeList[idx1]; } for (int colId = 0; colId < timeRangeList.Count; colId++) { AppTypes.TimeRanges timeRange = AppTypes.TimeRangeFromCode(timeRangeList[colId]); decimal[][] profitList = DataAccess.Libs.Estimate_Matrix_Profit(timeRange, timeScaleCode, processCodeList, strategyList, estimateOption); for (int idx1 = 0; idx1 < profitList.Length; idx1++) { DataTable tbl = resulTblList[idx1] as DataTable; for (int idx2 = 0; idx2 < profitList[idx1].Length; idx2++) { tbl.Rows[idx2][colId + 1] = profitList[idx1][idx2]; } } Application.DoEvents(); } progressBar.Value = codeEndIdx + 1; this.ShowReccount(progressBar.Value.ToString() + "/" + progressBar.Maximum.ToString()); codeStartIdx = codeEndIdx + 1; } }
public void PlotStrategyTradepoints(application.Strategy.StrategyMeta meta, bool showEstimation, EstimateTradePointFunc estimateFunc) { int idx; ShowMessage(""); EstimateOptions estOption = new EstimateOptions(); databases.tmpDS.tradeEstimateDataTable tbl = new databases.tmpDS.tradeEstimateDataTable(); application.StrategyStatistics statistics = new StrategyStatistics(); //TradePointInfo[] tradePoints = DataAccess.Libs.GetTradePointWithEstimationDetail(myData.myDataParam, myData.DataStockCode, meta.Code, estOption, out tbl, out statistics); /// Estimate trade points and set tradepoint's [isValid] property to mark whether a tradepoint is valid or not. for (idx = 0; idx < tradePoints.Length; idx++) { tradePoints[idx].isValid = !tbl[idx].ignored; } for (idx = tradePoints.Length - 1; idx > 0; idx--) { if (tradePoints[idx].isValid) { break; } } TradePointInfo tpiTradePointInfo = (TradePointInfo)tradePoints[idx]; BusinessInfo biLastTrade = tpiTradePointInfo.BusinessInfo; BusinessInfo biLastPoint = tradePoints[tradePoints.Length - 1].BusinessInfo; double price = myData.Close[myData.Close.Count - 1]; double risk = (biLastPoint.Short_Resistance - price) / (price - biLastPoint.Short_Support); //string sResult = "Close price=" + price+ // "Target="+biLastTrade.Short_Target+ // "Resistance=" + biLastPoint.Short_Resistance + // " Support=" + biLastPoint.Short_Support + // " Risk return=" +risk+ // " Winning Percentage:"+ String.Format("{0:P2}",statistics.dWinningPercentagePerTrade)+ // " Max %Win Per Trade:" + String.Format("{0:P2}",statistics.dMaxWinningPercentage)+ // " Max %Lose Per Trade" + String.Format("{0:P2}", statistics.dMaxLosingPercentage)+ // " Average %Win Per Trade" + String.Format("{0:P2}", statistics.dAverageWinningPercentage)+ // " Average %Lose Per Trade" + String.Format("{0:P2}", statistics.dAverageLosingPercentage); ; PlotStrategyTradepoints(application.Strategy.StrategyLibs.ToTradePoints(tradePoints), pricePanel); //MessageBox.Show(sResult); //Show form Tools.Forms.TradeStatistics formStatistic = new Tools.Forms.TradeStatistics(); formStatistic.AddStatisticInfo("Close price", price); formStatistic.AddStatisticInfo("Target", biLastTrade.Short_Target); formStatistic.AddStatisticInfo("Resistance", biLastPoint.Short_Resistance); formStatistic.AddStatisticInfo("Support", biLastPoint.Short_Support); formStatistic.AddStatisticInfo("Risk return", risk); formStatistic.AddStatisticInfo("Winning Percentage", String.Format("{0:P2}", statistics.dWinningPercentagePerTrade)); formStatistic.AddStatisticInfo("Max %Win Per Trade", String.Format("{0:P2}", statistics.dMaxWinningPercentage)); formStatistic.AddStatisticInfo("Max %Lose Per Trade", String.Format("{0:P2}", statistics.dMaxLosingPercentage)); formStatistic.AddStatisticInfo("Average %Win Per Trade", String.Format("{0:P2}", statistics.dAverageWinningPercentage)); formStatistic.AddStatisticInfo("Average %Lose Per Trade", String.Format("{0:P2}", statistics.dAverageLosingPercentage)); formStatistic.Show(this.DockPanel, DockState.DockRightAutoHide); //Call estimation handler if any. if (showEstimation && estimateFunc != null) { estimateFunc(this, meta.Code, estOption, tbl); } }
/// <summary> /// Estimate the profit from advices produced by analysis process. /// The function will produce a list of "transactions" assuming to be done from analysis advices. /// </summary> /// <param name="data"> Data used for analysis </param> /// <param name="tradePoints">Trade point list generated by analysis process</param> /// <param name="options">User- specific options : captital, max Buy...</param> /// <param name="returnObj">Returned object </param> /// <param name="afterEachEstimationFunc">Call-back function at the end of each tradepoind estimation</param> /// <param name="afterEstimationFunc">Call-back function at the end of estimation process</param> /// public static void EstimateTrading(AnalysisData data, TradePointInfo[] tradePoints, EstimateOptions options, object returnObj, AfterEachEstimationFunc afterEachEstimationFunc, AfterEstimationFunc afterEstimationFunc) { EstimationData myEstimationData = new EstimationData(); global::databases.baseDS.stockExchangeRow marketRow = databases.DbAccess.GetStockExchange(data.DataStockCode); decimal initCapAmt = options.TotalCapAmt * options.MaxBuyAmtPerc / 100; decimal priceWeight = marketRow.priceRatio; decimal feePerc = marketRow.tranFeePerc / 100; short buy2SellInterval = marketRow.minBuySellDay; databases.baseDS.stockCodeRow stockCodeRow = application.SysLibs.FindAndCache_StockCode(data.DataStockCode); if (stockCodeRow == null) { return; } int transDataIdx, lastBuyId = -1; decimal stockQty = 0, qty; decimal maxBuyQty = (decimal)(stockCodeRow.noOutstandingStock * options.MaxBuyQtyPerc / 100); decimal stockAmt = 0, stockPrice = 0, amt, feeAmt, totalFeeAmt = 0; decimal cashAmt = initCapAmt; //DateTime transDate = common.Consts.constNullDate; ; for (int idx = 0; idx < tradePoints.Length; idx++) { transDataIdx = tradePoints[idx].DataIdx; qty = 0; amt = 0; myEstimationData.ignored = false; stockPrice = (decimal)data.Close[transDataIdx]; switch (tradePoints[idx].TradeAction) { case AppTypes.TradeActions.Buy: //Assume that we can only buy if we have money qty = (stockPrice == 0 ? 0 : Math.Floor(cashAmt / ((stockPrice * priceWeight) * (1 + feePerc)))); if (qty > maxBuyQty) { qty = maxBuyQty; } if (qty != 0) { amt = qty * stockPrice * priceWeight; stockAmt += amt; stockQty += qty; feeAmt = Math.Round(amt * feePerc, 0); cashAmt -= amt + feeAmt; totalFeeAmt += feeAmt; lastBuyId = transDataIdx; } else { myEstimationData.ignored = true; } break; case AppTypes.TradeActions.Sell: //Can sell if own some stock if (stockQty <= 0) { myEstimationData.ignored = true; break; } // Not applicable to sell if (lastBuyId < 0) { myEstimationData.ignored = true; break; } //========================== // Check T+4 contrainst //========================== int minAllowSellPointIdx = lastBuyId + buy2SellInterval; // [minAllowSellPoint] is out of data bound , ignore it. if (minAllowSellPointIdx >= data.DateTime.Count) { myEstimationData.ignored = true; } // Violate T4 contrainst ? if (!myEstimationData.ignored && tradePoints[idx].DataIdx < minAllowSellPointIdx) { // Keep inapplicable Sells ?? if (Settings.sysKeepInApplicableSell) { //If it is the last trade point, make transaction (sell) at [minAllowSellPoint] if (idx >= tradePoints.Length - 1) { transDataIdx = minAllowSellPointIdx; } else { //If there is some trade point between it and [minAllowSellPoint], ignore it if (tradePoints[idx + 1].DataIdx < minAllowSellPointIdx) { myEstimationData.ignored = true; } else { transDataIdx = minAllowSellPointIdx; } } } else { myEstimationData.ignored = true; } } //Ok, sell it if (myEstimationData.ignored != true) { stockPrice = (decimal)data.Close[transDataIdx]; qty = stockQty; amt = qty * stockPrice * priceWeight; stockQty = 0; stockAmt = 0; feeAmt = Math.Round(amt * feePerc, 0); cashAmt += amt - feeAmt; totalFeeAmt += feeAmt; //Adjust trade point to refresh chages by T4 constrainst tradePoints[idx].DataIdx = transDataIdx; } else { tradePoints[idx].isValid = false; } break; } myEstimationData.tradeAction = tradePoints[idx].TradeAction; myEstimationData.onDate = DateTime.FromOADate(data.DateTime[transDataIdx]); myEstimationData.price = stockPrice; myEstimationData.qty = qty; myEstimationData.amt = amt; myEstimationData.feeAmt = totalFeeAmt; myEstimationData.ownedQty = stockQty; myEstimationData.ownedAmt = stockAmt; myEstimationData.cashAmt = cashAmt; myEstimationData.profitAmt = cashAmt + stockAmt - initCapAmt; if (afterEachEstimationFunc != null) { afterEachEstimationFunc(myEstimationData, returnObj); } } if (afterEstimationFunc != null) { afterEstimationFunc(myEstimationData, returnObj); } }