public bool Compare(IndicatorValues p1, IndicatorValues p2) { bool r = true; foreach (string k in p1.parametrs.Keys) { if (!p2.parametrs.ContainsKey(k) || p2.parametrs[k] != p1.parametrs[k]) { r = false; break; } } return(r); }
private void OneThreadTester(object p) { //DateTime lastDtBadIndicator; GlassGraph threadGlassVisual = new GlassGraph(); ResultOneThreadSumm resTh = new ResultOneThreadSumm(); List <int> oldGlassValue = new List <int>(); List <int> tempListForIndicator = new List <int>(); List <int> tempListForIndicatorAverage = new List <int>(); SortedDictionary <int, int> glass = new SortedDictionary <int, int>(); ParametrsForTest paramTh = (p as ParametrsForTestObj).paramS; Dictionary <string, DataTableWithCalcValues> dictionaryDT = (p as ParametrsForTestObj).dictionaryDT; int priceEnterLong, priceEnterShort; //IndicatorValuesAggregate aggreValues = new IndicatorValuesAggregate(new TimeSpan(TimeSpan.TicksPerMillisecond * 100)); // 100 мс //TimeSpan timeLong = new TimeSpan(); //TimeSpan timeShort = new TimeSpan(); IndicatorValues calculatedIndidcator; bool isCalculatedIndicator; DateTime startThread = DateTime.Now; foreach (string k in dictionaryDT.Keys) { //aggreValues.Reset(); lock (lockObj) { isCalculatedIndicator = true; IndicatorValues tempIval = new IndicatorValues(paramTh, ModeIndicator.glassInterest); calculatedIndidcator = (p as ParametrsForTestObj).dictionaryDT[k].indicatorvalues.Find(x => x.Compare(x, tempIval)); if (calculatedIndidcator == null) { isCalculatedIndicator = false; (p as ParametrsForTestObj).dictionaryDT[k].indicatorvalues.Add(tempIval); calculatedIndidcator = (p as ParametrsForTestObj).dictionaryDT[k].indicatorvalues.Find(x => x.Compare(x, tempIval)); } } while (isCalculatedIndicator && !calculatedIndidcator.CalculatedFinish) // ждем, пока другой поток завершит рассчет и затем начинаем использовать прощитанные значения { } glass.Clear(); oldGlassValue.Clear(); tempListForIndicator.Clear(); //lastDtBadIndicator = new DateTime(); priceEnterLong = 0; priceEnterShort = 0; bool indicatorGoToZero = false; int lotCount = 1; int? bid = 0, ask = 0; ResultOneThread resThTemp = new ResultOneThread(); int lossLongValueTemp = paramTh.lossLongValue, profitLongValueTemp = paramTh.profitLongValue; int lossShortValueTemp = paramTh.lossShortValue, profitShortValueTemp = paramTh.profitShortValue; resThTemp.shortName = k; DealInfo dealTemp = null; DataTable dt = dictionaryDT[k].datatable;//.Copy(); threadGlassVisual.visualAllElements.levelstartglass = (int)paramTh.averageValue; threadGlassVisual.visualAllElements.levelheightglass = paramTh.glassHeight; threadGlassVisual.visualAllElements.levelignoreval = paramTh.indicatorEnterValue; threadGlassVisual.visualAllElements.levelrefilling = paramTh.indicatorExitValue; int indicator = 0; int iterationNum = 0; // счетчик строк в текущей DataTable int? pricetick = 0; byte? actiontick = 0; double? volumetick = 0; int martinLevelTemp = 1; DateTime dtCurrentRow = new DateTime(); foreach (DataRow dr in dt.Rows) { #region торговля if (DoVisualisation && iterationNum != 0) { if (OnInformation != null) { OnInformation(InfoElement.tbInformation, dr.Field <DateTime>("dtserver").ToString(@"hh\:mm\:ss\.fff")); OnInformation(InfoElement.tbInfo2, "ind " + indicator.ToString()); } if (speedvisual >= 0) { Thread.Sleep(new TimeSpan((int)(dr.Field <DateTime>("dtserver").Subtract(dtCurrentRow).TotalMilliseconds *(speedvisual + 1) * 10000))); } else { Thread.Sleep(new TimeSpan((int)(dr.Field <DateTime>("dtserver").Subtract(dtCurrentRow).TotalMilliseconds / Math.Abs(speedvisual) * 10000))); } } dtCurrentRow = dr.Field <DateTime>("dtserver"); // совершена сделка if (!dr.IsNull("priceTick") && (pricetick = (int?)dr.Field <float?>("priceTick")) > 0)// && pricetick != (int?)dr.Field<float?>("priceTick")) // вторая часть условия - если перед этим была таже цена - пропускаем { if (indicator == 0) { indicatorGoToZero = true; } actiontick = dr.Field <byte?>("idaction"); volumetick = dr.Field <float?>("volumetick"); if (DoVisualisation && OnAddTick != null) { OnAddTick(dtCurrentRow, (double)pricetick, (double)volumetick, actiontick == 2 ? ActionGlassItem.sell : ActionGlassItem.buy); } if (priceEnterShort != 0 && indicator > 0 && actiontick == 1) { indicatorGoToZero = false; if (priceEnterShort - ask >= symbolStep) { resThTemp.countPDeal++; resThTemp.profit += (priceEnterShort - (int)ask) * lotCount; } else { resThTemp.countLDeal++; resThTemp.loss += ((int)ask - priceEnterShort) * lotCount;; } dealTemp.DoExit(dtCurrentRow, (float)ask); resThTemp.lstAllDeals.Add(dealTemp); priceEnterShort = 0; // профит короткая //if (priceEnterShort - profitShortValueTemp >= ask) //{ // resThTemp.countPDeal++; // resThTemp.profit += (priceEnterShort - (int)ask) * lotCount; // priceEnterShort = 0; // dealTemp.DoExit(dtCurrentRow, (float)ask); // //dealTemp.aggreeIndV = aggreValues.ResultAggregate; // resThTemp.lstAllDeals.Add(dealTemp); //} // лосс короткая //else if (indicator > 0) //{ // resThTemp.countLDeal++; // int g = ((int)ask - priceEnterShort) * lotCount; // resThTemp.loss += g; // dealTemp.DoExit(dtCurrentRow, (float)ask); // resThTemp.lstAllDeals.Add(dealTemp); // priceEnterShort = 0; // priceEnterLong = (int)ask; // lotCount += 1; // dealTemp = new DealInfo(ActionDeal.buy, dtCurrentRow, lotCount, priceEnterLong, indicator); //} //else if (priceEnterShort + lossShortValueTemp <= ask) //{ //if (paramTh.martingValue >= martinLevelTemp)// && indicator < 0) //{ //martinLevelTemp++; //lotCount += 1; //dealTemp.lotsCount = lotCount; //int delt = (int)Math.Truncate((double)((int)ask - priceEnterShort) / lotCount / 10) * 10; //profitShortValueTemp = paramTh.profitShortValue + 2 * delt; //lossShortValueTemp = paramTh.lossShortValue + delt; //priceEnterShort = priceEnterShort + (int)((int)ask - priceEnterShort) / lotCount; //if (dealTemp.lstSubDeal.Count > 0) // dealTemp.lstSubDeal.Last().dtDealLength = dtCurrentRow.TimeOfDay.Subtract(dealTemp.lstSubDeal.Last().dtEnter); //dealTemp.lstSubDeal.Add(new SubDealInfo(dtCurrentRow, lotCount, ActionDeal.subsell, (float)priceEnterShort, (float)ask, (float)delt, indicator, (float)lossShortValueTemp, (float)profitShortValueTemp)); //dealTemp.lstSubDeal.Last().aggreeIndV = aggreValues.ResultAggregate; //} //else //{ //resThTemp.countLDeal++; //int g = ((int)ask - priceEnterShort) * lotCount; //resThTemp.loss += g; //dealTemp.DoExit(dtCurrentRow, (float)ask); //dealTemp.aggreeIndV = aggreValues.ResultAggregate; //resThTemp.lstAllDeals.Add(dealTemp); //priceEnterShort = 0; //lotCount = 1; //} //} // трейлим профит //else if ((ask - paramTh.profitShortValue - 20 > priceEnterShort - profitShortValueTemp) && profitShortValueTemp > 20) //{ // profitShortValueTemp = priceEnterShort - (int)ask + paramTh.profitShortValue; //} } else if (priceEnterLong != 0 && indicator < 0 && actiontick == 2) { indicatorGoToZero = false; if (bid - priceEnterLong >= symbolStep) { resThTemp.countPDeal++; resThTemp.profit += ((int)bid - priceEnterLong) * lotCount; } else { resThTemp.countLDeal++; resThTemp.loss += (priceEnterLong - (int)bid) * lotCount; } dealTemp.DoExit(dtCurrentRow, (float)bid); resThTemp.lstAllDeals.Add(dealTemp); priceEnterLong = 0; // профит длиная //if (priceEnterLong + profitLongValueTemp <= bid) //{ // resThTemp.countPDeal++; // resThTemp.profit += ((int)bid - priceEnterLong) * lotCount; // priceEnterLong = 0; // dealTemp.DoExit(dtCurrentRow, (float)bid); // //dealTemp.aggreeIndV = aggreValues.ResultAggregate; // resThTemp.lstAllDeals.Add(dealTemp); //} // лосс длиная //else if (indicator < 0) //{ // resThTemp.countLDeal++; // int g = (priceEnterLong - (int)bid) * lotCount; // resThTemp.loss += g; // dealTemp.DoExit(dtCurrentRow, (float)bid); // resThTemp.lstAllDeals.Add(dealTemp); // priceEnterLong = 0; // priceEnterShort = (int)bid; // lotCount += 1; // dealTemp = new DealInfo(ActionDeal.sell, dtCurrentRow, lotCount, priceEnterShort, indicator); //} //else if (priceEnterLong - lossLongValueTemp >= bid) //{ //if (paramTh.martingValue >= martinLevelTemp) //&& indicator > 0) //{ //martinLevelTemp++; //lotCount += 1; //dealTemp.lotsCount = lotCount; //int delt = (int)Math.Truncate((double)(priceEnterLong - (int)bid) / lotCount / 10) * 10; //profitLongValueTemp = paramTh.profitLongValue + 2 * delt; //lossLongValueTemp = paramTh.lossLongValue + delt; //priceEnterLong = priceEnterLong - (int)(priceEnterLong - (int)bid) / lotCount; //if (dealTemp.lstSubDeal.Count > 0) // dealTemp.lstSubDeal.Last().dtDealLength = dtCurrentRow.TimeOfDay.Subtract(dealTemp.lstSubDeal.Last().dtEnter); //dealTemp.lstSubDeal.Add(new SubDealInfo(dtCurrentRow, lotCount, ActionDeal.subbuy, (float)priceEnterLong, (float)bid, (float)delt, indicator, (float)lossLongValueTemp, (float)profitLongValueTemp)); //dealTemp.lstSubDeal.Last().aggreeIndV = aggreValues.ResultAggregate; //} //else //{ //resThTemp.countLDeal++; //int g = (priceEnterLong - (int)bid) * lotCount; //resThTemp.loss += g; //dealTemp.DoExit(dtCurrentRow, (float)bid); //dealTemp.aggreeIndV = aggreValues.ResultAggregate; //resThTemp.lstAllDeals.Add(dealTemp); //priceEnterLong = 0; //lotCount = 1; //} //} // трейлим профит //else if ((bid + paramTh.profitLongValue < priceEnterLong + profitLongValueTemp - 20) && profitLongValueTemp > 20) //{ // profitLongValueTemp = (int)bid + paramTh.profitLongValue - priceEnterLong; //} } if (indicator > 0 && priceEnterLong == 0 && priceEnterShort == 0 && indicatorGoToZero && actiontick == 1) { lossLongValueTemp = paramTh.lossLongValue; profitLongValueTemp = paramTh.profitLongValue; priceEnterLong = (int)ask; lotCount = 1; martinLevelTemp = 1; dealTemp = new DealInfo(ActionDeal.buy, dtCurrentRow, 1, priceEnterLong, indicator); } // вход шорт else if (indicator < 0 && priceEnterLong == 0 && priceEnterShort == 0 && indicatorGoToZero && actiontick == 2) { lossShortValueTemp = paramTh.lossShortValue; profitShortValueTemp = paramTh.profitShortValue; priceEnterShort = (int)bid; lotCount = 1; martinLevelTemp = 1; dealTemp = new DealInfo(ActionDeal.sell, dtCurrentRow, 1, priceEnterShort, indicator); } } // изменение в стакане else if (!dr.IsNull("price")) { int updatepricegl = (int)dr.Field <float?>("price"); int updatevolumegl = (int)dr.Field <float?>("volume"); int rownum = (int)dr.Field <int?>("rownum"); int typeprice = (int)dr.Field <int?>("typeprice"); if (rownum == 0) { if (typeprice == 1) { ask = updatepricegl; } else if (typeprice == 2) { bid = updatepricegl; } } if (DoVisualisation && OnChangeGlass != null) { OnChangeGlass(dtCurrentRow, updatepricegl, updatevolumegl, rownum, typeprice == 1 ? ActionGlassItem.sell : ActionGlassItem.buy); } if (!glass.ContainsKey(updatepricegl)) { glass.Add(updatepricegl, updatevolumegl); } else { glass[updatepricegl] = updatevolumegl; if (glass.Count > 50) { DateTime dttemp = dtCurrentRow; if (!isCalculatedIndicator) { int sumGlass = 0; // среднее значение по стакану for (int i = 0; i < 50 /*threadGlassVisual.visualAllElements.LevelHeightGlass*/; i++) { sumGlass += glass.ContainsKey((int)(ask + i * symbolStep)) ? (int)glass[(int)(ask + i * symbolStep)] : 0; sumGlass += glass.ContainsKey((int)(bid - i * symbolStep)) ? (int)glass[(int)(bid - i * symbolStep)] : 0; } int averageGlass = (int)sumGlass / (50 /*threadGlassVisual.visualAllElements.LevelHeightGlass*/ * 2); int sumlong = 0, sumshort = 0; int sumlongAverage = 0, sumshortAverage = 0; tempListForIndicator.Clear(); tempListForIndicatorAverage.Clear(); // новая версия, более взвешенное значение (как год назад) for (int i = 0; i < 50 /*paramTh.glassHeight*/; i++) { if (glass.ContainsKey((int)(ask + i * symbolStep))) { sumlong += (int)glass[(int)(ask + i * symbolStep)]; } if (glass.ContainsKey((int)(bid - i * symbolStep))) { sumshort += (int)glass[(int)(bid - i * symbolStep)]; } sumlongAverage += glass.ContainsKey((int)(ask + i * symbolStep)) && glass[(int)(ask + i * symbolStep)] < averageGlass * 100 //paramTh.averageValue ? (int)glass[(int)(ask + i * symbolStep)] : averageGlass * 100; //(int)paramTh.averageValue; sumshortAverage += glass.ContainsKey((int)(bid - i * symbolStep)) && glass[(int)(bid - i * symbolStep)] < averageGlass * 100 //paramTh.averageValue ? (int)glass[(int)(bid - i * symbolStep)] : averageGlass * 100; // (int)paramTh.averageValue; if (sumlong + sumshort == 0) { continue; } tempListForIndicator.Add((int)(sumlong - sumshort) * 100 / (sumlong + sumshort)); int tempsumavr = (sumlongAverage + sumshortAverage) == 0 ? 1 : sumlongAverage + sumshortAverage; tempListForIndicatorAverage.Add((int)(sumlongAverage - sumshortAverage) * 100 / tempsumavr); } lock (lockObj) { ResultOneTick r = new ResultOneTick(); threadGlassVisual.visualAllElements.CalcSummIndicatorValue(tempListForIndicatorAverage.ToArray(), r); if (!calculatedIndidcator.values.ContainsKey(dttemp)) { calculatedIndidcator.values.Add(dttemp, r.valPresetHeight); } } } else { indicator = (int)calculatedIndidcator.values[dttemp]; } } } } // Обновление котировок else if (!dr.IsNull("bid")) { bid = (int)dr.Field <float?>("bid"); ask = (int)dr.Field <float?>("ask"); } iterationNum++; if (iterationNum == dt.Rows.Count) { #region Закрыть последнюю сделку, если данные закончились (эмитируем отключение программы) if (priceEnterLong != 0) { if (bid - priceEnterLong > 0) { resThTemp.countPDeal++; resThTemp.profit += ((int)bid - priceEnterLong) * lotCount; } else { resThTemp.countLDeal++; resThTemp.loss += (priceEnterLong - (int)bid) * lotCount; } dealTemp.DoExit(dtCurrentRow, (float)bid); //dealTemp.aggreeIndV = aggreValues.ResultAggregate; resThTemp.lstAllDeals.Add(dealTemp); priceEnterLong = 0; lotCount = 1; } if (priceEnterShort != 0) { if (priceEnterShort - ask > 0) { resThTemp.countPDeal++; resThTemp.profit += (priceEnterShort - (int)ask) * lotCount; } else { resThTemp.countLDeal++; resThTemp.loss += ((int)ask - priceEnterShort) * lotCount; } dealTemp.DoExit(dtCurrentRow, (float)ask); //dealTemp.aggreeIndV = aggreValues.ResultAggregate; resThTemp.lstAllDeals.Add(dealTemp); priceEnterShort = 0; lotCount = 1; } continue; #endregion } #endregion торговля } // конец цикла по строка DataTable lock (lockObj) { if (!calculatedIndidcator.CalculatedFinish) { calculatedIndidcator.CalculatedFinish = true; } } resThTemp.margin = resThTemp.profit - resThTemp.loss; resThTemp.profitFac = (float)resThTemp.profit / (float)resThTemp.loss; // математическое ожидание resThTemp.matExp = (1 + ((float)resThTemp.profit / (float)resThTemp.countPDeal) / ((float)resThTemp.loss / (float)resThTemp.countLDeal)) * ((float)resThTemp.countPDeal / ((float)resThTemp.countPDeal + (float)resThTemp.countLDeal)) - 1; resTh.AddOneDayResult(resThTemp); } lock (lockObj) { resTh.idCycle = (p as ParametrsForTestObj).numThread; resTh.mutC = (p as ParametrsForTestObj).mutationCount.ToString() + "|" + DateTime.Now.Subtract(startThread).TotalSeconds.ToString() + "с"; resTh.idParam = paramTh.id; resTh.paramForTest = paramTh; resTh.glassH = paramTh.glassHeight; resTh.indicLongVal = paramTh.indicatorEnterValue; resTh.indicShortVal = paramTh.indicatorExitValue; resTh.profLongLevel = paramTh.profitLongValue; resTh.lossLongLevel = paramTh.lossLongValue; resTh.profShortLevel = paramTh.profitShortValue; resTh.lossShortLevel = paramTh.lossShortValue; resTh.martinLevel = paramTh.martingValue; resTh.delay = paramTh.delay; resTh.averageVal = paramTh.averageValue; resTh.margin = resTh.profit - resTh.loss; resTh.matExp = (1 + ((float)resTh.profit / (float)resTh.countPDeal) / ((float)resTh.loss / (float)resTh.countLDeal)) * ((float)resTh.countPDeal / ((float)resTh.countPDeal + (float)resTh.countLDeal)) - 1; if (resTh.loss == 0 && resTh.profit == 0) { resTh.profitFac = -1; } else if (resTh.loss == 0) { resTh.profitFac = 999; } else { resTh.profitFac = (float)resTh.profit / (float)resTh.loss; } ResultBestProfitFactor rp = new ResultBestProfitFactor(resTh.idParam, resTh.profitFac, resTh.margin, resTh.matExp); if (!dicAllProfitResult.ContainsKey(rp)) { dicAllProfitResult.Add(rp, resTh); } if (OnFinishOneThread != null) { OnFinishOneThread(resTh); } } }