using IndexFormula.Finance; using IndexFormula.Finance.DataProvider; using IndexFormula.Finance.Win; using MuchInfo.Chart.Data.EnumTypes; using MuchInfo.Chart.Data.Models; using MuchInfo.Chart.Utilities.Enums; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Threading; using System.Windows; using System.Windows.Forms; namespace MuchInfo.Chart.DataAdapter { public class DataService : IDataService { /// /// 使用公式计算图表数据 /// /// 源数据,需要计算的数据 /// 返回图表数据 public List Calculate(List source, List sourceCharts, Data.EnumTypes.CycleType cycleType, TimeSpan minutes) { var commonDataProvider = new CommonDataProvider(null); commonDataProvider.LoadBinary(ConvertData(source)); commonDataProvider.DataCycle = ConvertCycle(cycleType, minutes); foreach (var formulaModel in sourceCharts) { try { var formulaBase = FormulaBase.GetFormulaByName(formulaModel.FormulaName); var formulaPackage = formulaBase.Run(commonDataProvider); if (formulaPackage.Count > 0) { for (int i = 0; i < formulaPackage.Count - 1; i++) { var indicatorModel = formulaModel.IndicatorList.FirstOrDefault((model) => model.LineName == formulaPackage[i].Name); if (indicatorModel == null) continue; indicatorModel.CalculateDataPoints = ConvertDataPoint(formulaPackage[i].Data, commonDataProvider["DATE"]); } } } catch { //找到不公式跳过,不影响下一个 } } return sourceCharts; } /// /// 使用公式计算图表数据 /// /// 源数据,需要计算的数据 /// 公式 /// 周期类型 /// 自定义周期分钟数 /// 返回图表数据 public FormulaModel Calculate(List source, FormulaModel formula, Data.EnumTypes.CycleType cycleType, TimeSpan minutes) { var commonDataProvider = new CommonDataProvider(null); commonDataProvider.LoadBinary(ConvertData(source)); commonDataProvider.DataCycle = ConvertCycle(cycleType, minutes); try { var formulaBase = FormulaBase.GetFormulaByName(formula.FormulaName); var formulaPackage = formulaBase.Run(commonDataProvider); if (formulaPackage.Count > 0) { if (formula.IndicatorList == null) { formula.IndicatorList = new List(); } formula.IndicatorList.Clear(); for (int i = 0; i < formulaPackage.Count; i++) { var indicatorModel = FormulaDataCovnert(formulaPackage[i], formula, commonDataProvider["DATE"]); formula.IndicatorList.Add(indicatorModel); } } } catch { //找到不公式跳过,不影响下一个 } return formula; } /// /// 打开指标编辑器 /// /// 计算源数据 /// 当前图表的所有计算公式 /// 周期类型 /// 自定义周期分钟数 /// 返回图表数据 public List OpenEditor(List source, string[] formulaArray, Data.EnumTypes.CycleType cycleType, TimeSpan minutes) { string selectFormula = (formulaArray != null && formulaArray.Any()) ? formulaArray[0] : ""; Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(SetLanguage.languageName); var manager = new FormulaManager(); if (manager.ShowForm(formulaArray, selectFormula) == DialogResult.OK) { //公式之间用#号隔开 string[] currentFormulas = manager.CurrentFormulas.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries); var commonDataProvider = new CommonDataProvider(null); //todo:以下内容考虑用线程实现 commonDataProvider.LoadBinary(ConvertData(source)); commonDataProvider.DataCycle = ConvertCycle(cycleType, minutes); var formulas = new List(); foreach (var formula in currentFormulas) { try { var formulaModel = new FormulaModel(); var formulaBase = FormulaBase.GetFormulaByName(formula); var formulaPackage = formulaBase.Run(commonDataProvider); if (formulaPackage.Count > 0) { var indicatorModels = new List(); for (int i = 0; i < formulaPackage.Count; i++) { var indicatorModel = FormulaDataCovnert(formulaPackage[i], formulaModel, commonDataProvider["DATE"]); indicatorModels.Add(indicatorModel); } formulaModel.FormulaName = formulaBase.FormulaName; formulaModel.IndicatorList = indicatorModels; formulas.Add(formulaModel); } } catch (Exception ex) { //找到不公式跳过,不影响下一个 // throw; } } return formulas; } return null; } /// /// 将编辑器计算的数据生成转换生成图表数据 /// /// 计算后的数据 /// 生成图表数据 private IndicatorModel FormulaDataCovnert(FormulaData formulaData, FormulaModel formulaModel, double[] dateTime) { var indicator = new IndicatorModel(formulaModel); indicator.Alpha = formulaData.Alpha; if (formulaData.AreaBrush is System.Drawing.SolidBrush) //只处理单色 { SolidBrush solidBrush = formulaData.AreaBrush as System.Drawing.SolidBrush; indicator.AreaBrush = System.Windows.Media.Color.FromArgb (solidBrush.Color.A, solidBrush.Color.R, solidBrush.Color.G, solidBrush.Color.B); } if (formulaData.FormulaUpColor != System.Drawing.Color.Empty) { indicator.UpBrush = System.Windows.Media.Color.FromArgb(formulaData.FormulaUpColor.A, formulaData.FormulaUpColor.R, formulaData.FormulaUpColor.G, formulaData.FormulaUpColor.B); } if (formulaData.FormulaDownColor != System.Drawing.Color.Empty) { indicator.DownBrush = System.Windows.Media.Color.FromArgb(formulaData.FormulaDownColor.A, formulaData.FormulaDownColor.R, formulaData.FormulaDownColor.G, formulaData.FormulaDownColor.B); } indicator.CalculateDataPoints = ConvertDataPoint(formulaData.Data, dateTime); // indicator.SubData = formulaData.SubData; indicator.DataFormat = formulaData.Format; indicator.LineName = formulaData.Name; indicator.LineWidth = formulaData.LineWidth; #region 还有多种未对应 switch (formulaData.DashStyle) { case System.Drawing.Drawing2D.DashStyle.Custom: //未设置 indicator.DashStyleType = DashStyleType.Dashed; break; case System.Drawing.Drawing2D.DashStyle.Dash: indicator.DashStyleType = DashStyleType.Dashed; break; case System.Drawing.Drawing2D.DashStyle.DashDot:// indicator.DashStyleType = DashStyleType.Dashed; break; case System.Drawing.Drawing2D.DashStyle.DashDotDot: indicator.DashStyleType = DashStyleType.LongDashes; // break; case System.Drawing.Drawing2D.DashStyle.Dot: indicator.DashStyleType = DashStyleType.Dotted; break; case System.Drawing.Drawing2D.DashStyle.Solid: indicator.DashStyleType = DashStyleType.Solid; break; default: indicator.DashStyleType = DashStyleType.Solid; break; } #endregion #region 图表类型未一一对应 switch (formulaData.RenderType) { case FormulaRenderType.NORMAL: indicator.LinePlotType = LinePlotType.Line; break; case FormulaRenderType.COLORSTICK: indicator.LinePlotType = LinePlotType.Bar; indicator.PlotNegValsDiffColor = true; break; case FormulaRenderType.VOLSTICK: indicator.LinePlotType = LinePlotType.Bar; indicator.VolBar = true; break; case FormulaRenderType.STICKLINE: indicator.LinePlotType = LinePlotType.Bar; break; case FormulaRenderType.ICON: break; case FormulaRenderType.TEXT: break; case FormulaRenderType.POLY: break; case FormulaRenderType.FILLRGN: indicator.LinePlotType = LinePlotType.FillRGN; var doubleArray = formulaData.SubData["PRICE2"] as double[]; if (doubleArray != null) { indicator.SubData[indicator.FillRNGKey] = ConvertDataPoint(doubleArray, dateTime); } indicator.SubData[indicator.CondKey] = formulaData.SubData[indicator.CondKey]; break; case FormulaRenderType.FILLAREA: indicator.LinePlotType = LinePlotType.Area; break; case FormulaRenderType.PARTLINE: indicator.LinePlotType = LinePlotType.OHLC; break; case FormulaRenderType.LINE: indicator.LinePlotType = LinePlotType.Line; break; case FormulaRenderType.VERTLINE: break; case FormulaRenderType.AXISY: break; case FormulaRenderType.AXISYTEXT: break; case FormulaRenderType.STOCK: indicator.LinePlotType = LinePlotType.Candlestick; break; case FormulaRenderType.MONOSTOCK: indicator.LinePlotType = LinePlotType.Candlestick; break; default: break; } #endregion #region 点样式 switch (formulaData.Dot) { case FormulaDot.NORMAL: indicator.PointDotType = PointDotType.NORMAL; break; case FormulaDot.CROSSDOT: indicator.PointDotType = PointDotType.CROSSDOT; indicator.LinePlotType = LinePlotType.CROSSDOT; break; case FormulaDot.POINTDOT: indicator.PointDotType = PointDotType.POINTDOT; indicator.LinePlotType = LinePlotType.Dot; break; case FormulaDot.CIRCLEDOT: indicator.PointDotType = PointDotType.CIRCLEDOT; indicator.LinePlotType = LinePlotType.CIRCLEDOT; break; default: indicator.PointDotType = PointDotType.NORMAL; break; } #endregion indicator.LineWidth = formulaData.LineWidth; indicator.SameColor = formulaData.SameColor; return indicator; } /// /// 将使用公式计算数据转换成BarPoint /// /// 计算数据 /// /// private List ConvertDataPoint(double[] dataArray, double[] dateArray) { if (dataArray == null) return null; int index = 0; var BarPoints = new List(); if (dataArray.Length < dateArray.Length) { foreach (var d in dateArray) { if (index >= dataArray.Length) { var barPoint = new BarDataPoint(DateTime.FromOADate(d), BarPoints[index - 1].Value); BarPoints.Add(barPoint); } else { if (dataArray.Length == 0) { var barPoint = new BarDataPoint(DateTime.FromOADate(d), (float)dataArray[index]); BarPoints.Add(barPoint); } else { var barPoint = new BarDataPoint(DateTime.FromOADate(d), (float)dataArray[index]); BarPoints.Add(barPoint); } } index++; } } else { if (dataArray != null && dataArray.Count() > 0) { foreach (var d in dataArray) { if (!double.IsNaN(d)) { var barPoint = new BarDataPoint(DateTime.FromOADate(dateArray[index]), (float)d); BarPoints.Add(barPoint); index++; } } } } return BarPoints; } /// /// 转换周期 /// /// 周期类型 /// 分钟数据 /// 编辑器中的数据周期 private DataCycle ConvertCycle(Data.EnumTypes.CycleType cycleType, TimeSpan minutes) { switch (cycleType) { case CycleType.None: return DataCycle.Day; break; case CycleType.Tik: return DataCycle.Tick; case CycleType.Minute: return DataCycle.Minute; case CycleType.Minute3: return new DataCycle(DataCycleBase.MINUTE, 3); case CycleType.Minute5: return new DataCycle(DataCycleBase.MINUTE, 5); case CycleType.Minute10: return new DataCycle(DataCycleBase.MINUTE, 10); case CycleType.Minute15: return new DataCycle(DataCycleBase.MINUTE, 15); case CycleType.Minute30: return new DataCycle(DataCycleBase.MINUTE, 30); case CycleType.Minute60: return new DataCycle(DataCycleBase.MINUTE, 60); case CycleType.Minute90: return new DataCycle(DataCycleBase.MINUTE, 90); case CycleType.Minute120: return new DataCycle(DataCycleBase.MINUTE, 120); case CycleType.Minute180: return new DataCycle(DataCycleBase.MINUTE, 180); case CycleType.Minute240: return new DataCycle(DataCycleBase.MINUTE, 240); case CycleType.Hour: return DataCycle.Hour; case CycleType.Day: return DataCycle.Day; case CycleType.Week: return DataCycle.Week; case CycleType.Month: return DataCycle.Minute; case CycleType.Quarter: return DataCycle.Quarter; case CycleType.Year: return DataCycle.Year; case CycleType.Custom: return new DataCycle(DataCycleBase.MINUTE, (int)minutes.TotalMinutes); default: return DataCycle.Day; } } /// /// 将源数据转换成数组 /// /// 源数据 /// 返回open, high, low, close, volume, date数据组 private double[][] ConvertData(List source) { var opens = new double[source.Count]; var highs = new double[source.Count]; var lows = new double[source.Count]; var closes = new double[source.Count]; var volumes = new double[source.Count]; var dates = new double[source.Count]; for (int i = 0; i < source.Count; i++) { opens[i] = source[i].Open; highs[i] = source[i].High; lows[i] = source[i].Low; closes[i] = source[i].Close; volumes[i] = source[i].Volume; dates[i] = source[i].Date.ToOADate(); } return new double[][] { opens, highs, lows, closes, volumes, dates }; } /// /// 编辑公式 /// /// 公式名称 public void EditFormula(string formulaName) { MessageBoxManager.Unregister(); switch (SetLanguage.currentLanguage) { case ChartLanguageType.SimplifiedChinese: MessageBoxManager.Yes = "是"; MessageBoxManager.No = "否"; MessageBoxManager.Cancel = "取消"; break; case ChartLanguageType.TraditionalChinese: MessageBoxManager.Yes = "是"; MessageBoxManager.No = "否"; MessageBoxManager.Cancel = "取消"; break; case ChartLanguageType.English: MessageBoxManager.Yes = "Yes"; MessageBoxManager.No = "No"; MessageBoxManager.Cancel = "Cancel"; break; } //注册MessageBoxManager MessageBoxManager.Register(); var formulaBase = FormulaBase.GetFormulaByName(formulaName); string formulaFile = PluginManager.GetFormulaFile(formulaBase); if (formulaFile != null) { string directoryName = Path.GetDirectoryName(formulaFile); formulaFile = Path.GetFileNameWithoutExtension(formulaFile).Replace('_', '.'); formulaFile = directoryName + @"\" + formulaFile; if (File.Exists(formulaFile)) { Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(SetLanguage.languageName); FormulaSourceEditor.Open(formulaFile, formulaBase.GetType().ToString()); } } } public DataService() { SetLanguage.SetcurrentLanguage(ChartLanguageType.SimplifiedChinese); } /// /// 设置编辑器的语言 /// /// public void SetEditorLanguage(ChartLanguageType language) { SetLanguage.SetcurrentLanguage(language); } /// /// 从文件中加载公式 /// /// 文件名称 /// public SpaceModel LoadSpaceFromFile(string fileName) { if (string.IsNullOrEmpty(fileName)) //如fileName为空取主图指标的路径 { var formulaBase = FormulaBase.GetFormulaByName("Main"); string formulaFile = PluginManager.GetFormulaFile(formulaBase); if (formulaFile != null) { string directoryName = Path.GetDirectoryName(formulaFile); formulaFile = Path.GetFileNameWithoutExtension(formulaFile).Replace('_', '.'); fileName = directoryName + @"\" + formulaFile; } } var formulaSpace = FormulaSpace.Read(fileName); if (formulaSpace != null) { var spaceModel = new SpaceModel(); CovertToModel(spaceModel, formulaSpace); return spaceModel; } return null; } /// /// 转换Xml中公式命名对象 /// /// /// private void CovertToModel(SpaceModel model, FormulaSpace fs) { model.SpaceModels = new List(); model.ProgramModels = new List(); foreach (FormulaSpace space in fs.Namespaces) //加载命名空间 { SpaceModel modelItem = new SpaceModel(); modelItem.SpaceName = space.Name; model.SpaceModels.Add(modelItem); this.CovertToModel(modelItem, space); } if (fs.Programs != null) { foreach (FormulaProgram program in fs.Programs) { var programItem = new ProgramModel(); programItem.Name = program.Name; programItem.IsMainView = program.IsMainView; model.ProgramModels.Add(programItem); if (program.Params != null && program.Params.Count > 0) { foreach (var paramItem in program.Params) { var fParam = paramItem as FormulaParam; if (fParam != null && !string.IsNullOrEmpty(fParam.Name)) { programItem.DefaultParams[fParam.Name] = fParam.DefaultValue; programItem.CustomParams[fParam.Name] = new CustomParamModel() { Value = fParam.CustomValue }; } } } } } } /// /// 保存指标参数 /// /// 公式参数 public void SaveFormulaParams(List programModels) { if (programModels == null || !programModels.Any()) return; var dicFormulaSpace = new Dictionary(); foreach (var programModel in programModels) { var formulaBase = FormulaBase.GetFormulaByName(programModel.Name); if (formulaBase == null) continue; string formulaFile = PluginManager.GetFormulaFile(formulaBase); string directoryName = Path.GetDirectoryName(formulaFile); formulaFile = Path.GetFileNameWithoutExtension(formulaFile); if (!string.IsNullOrWhiteSpace(formulaFile)) { formulaFile = formulaFile.Replace('_', '.'); var fileName = directoryName + @"\" + formulaFile; FormulaProgram formulaProgram = null; if (!dicFormulaSpace.ContainsKey(fileName)) { var space = FormulaSpace.Read(fileName); if (space != null) { dicFormulaSpace[fileName] = space; formulaProgram = space.FindFormulaProgram(formulaBase); } } else { formulaProgram = dicFormulaSpace[fileName].FindFormulaProgram(formulaBase); } if (formulaProgram != null) { if (programModel.CustomParams != null && programModel.CustomParams.Keys.Any()) { foreach (var key in programModel.CustomParams.Keys) { if (formulaProgram.Params[key] != null) { formulaProgram.Params[key].CustomValue = programModel.CustomParams[key].Value; } } } } } } if (dicFormulaSpace.Any()) //保存参数到配置文件 { foreach (var key in dicFormulaSpace.Keys) { dicFormulaSpace[key].Write(key); } } } public void OpenFormulaEdit(string formulaName) { MessageBoxManager.Unregister(); switch (SetLanguage.currentLanguage) { case ChartLanguageType.SimplifiedChinese: MessageBoxManager.Yes = "是"; MessageBoxManager.No = "否"; MessageBoxManager.Cancel = "取消"; break; case ChartLanguageType.TraditionalChinese: MessageBoxManager.Yes = "是"; MessageBoxManager.No = "否"; MessageBoxManager.Cancel = "取消"; break; case ChartLanguageType.English: MessageBoxManager.Yes = "Yes"; MessageBoxManager.No = "No"; MessageBoxManager.Cancel = "Cancel"; break; } //注册MessageBoxManager MessageBoxManager.Register(); var formulaBase = FormulaBase.GetFormulaByName(formulaName); string formulaFile = PluginManager.GetFormulaFile(formulaBase); if (formulaFile != null) { string directoryName = Path.GetDirectoryName(formulaFile); formulaFile = Path.GetFileNameWithoutExtension(formulaFile).Replace('_', '.'); formulaFile = directoryName + @"\" + formulaFile; if (File.Exists(formulaFile)) { Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(SetLanguage.languageName); FormulaSourceEditor.Open(formulaFile, "FML."); } } } /// /// 转换DataPoint数据 /// /// 数据源 /// 周期 /// 自定义周期时间 /// public CommonDataProvider DataPointConvert(List source, CycleType cycleType, TimeSpan minutes,IDataManager dataManager) { var commonDataProvider = new CommonDataProvider(dataManager); if (source != null) { commonDataProvider.LoadBinary(ConvertData(source)); commonDataProvider.DataCycle = ConvertCycle(cycleType, minutes); } return commonDataProvider; } } }