FormulaHelpers.cs 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Globalization;
  8. using System.Text;
  9. namespace FastReport.DataVisualization.Charting.Formulas
  10. {
  11. #region class FormulaHelper
  12. /// <summary>
  13. /// Formula helper is a static utility class implementing common formula related routines.
  14. /// </summary>
  15. internal static class FormulaHelper
  16. {
  17. #region Static
  18. /// <summary>
  19. /// Gets the formula info instance.
  20. /// </summary>
  21. /// <param name="formula">The formula.</param>
  22. /// <returns>FomulaInfo instance</returns>
  23. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
  24. internal static FormulaInfo GetFormulaInfo(FinancialFormula formula)
  25. {
  26. switch (formula)
  27. {
  28. //Price indicators
  29. case FinancialFormula.MovingAverage:
  30. return new MovingAverageFormulaInfo();
  31. case FinancialFormula.ExponentialMovingAverage:
  32. return new ExponentialMovingAverageFormulaInfo();
  33. case FinancialFormula.WeightedMovingAverage:
  34. return new WeightedMovingAverageFormulaInfo();
  35. case FinancialFormula.TriangularMovingAverage:
  36. return new TriangularMovingAverageFormulaInfo();
  37. case FinancialFormula.TripleExponentialMovingAverage:
  38. return new TripleExponentialMovingAverageFormulaInfo();
  39. case FinancialFormula.BollingerBands:
  40. return new BollingerBandsFormulaInfo();
  41. case FinancialFormula.TypicalPrice:
  42. return new TypicalPriceFormulaInfo();
  43. case FinancialFormula.WeightedClose:
  44. return new WeightedCloseFormulaInfo();
  45. case FinancialFormula.MedianPrice:
  46. return new MedianPriceFormulaInfo();
  47. case FinancialFormula.Envelopes:
  48. return new EnvelopesFormulaInfo();
  49. case FinancialFormula.StandardDeviation:
  50. return new StandardDeviationFormulaInfo();
  51. // Oscilators
  52. case FinancialFormula.ChaikinOscillator:
  53. return new ChaikinOscillatorFormulaInfo();
  54. case FinancialFormula.DetrendedPriceOscillator:
  55. return new DetrendedPriceOscillatorFormulaInfo();
  56. case FinancialFormula.VolatilityChaikins:
  57. return new VolatilityChaikinsFormulaInfo();
  58. case FinancialFormula.VolumeOscillator:
  59. return new VolumeOscillatorFormulaInfo();
  60. case FinancialFormula.StochasticIndicator:
  61. return new StochasticIndicatorFormulaInfo();
  62. case FinancialFormula.WilliamsR:
  63. return new WilliamsRFormulaInfo();
  64. // General technical indicators
  65. case FinancialFormula.AverageTrueRange:
  66. return new AverageTrueRangeFormulaInfo();
  67. case FinancialFormula.EaseOfMovement:
  68. return new EaseOfMovementFormulaInfo();
  69. case FinancialFormula.MassIndex:
  70. return new MassIndexFormulaInfo();
  71. case FinancialFormula.Performance:
  72. return new PerformanceFormulaInfo();
  73. case FinancialFormula.RateOfChange:
  74. return new RateOfChangeFormulaInfo();
  75. case FinancialFormula.RelativeStrengthIndex:
  76. return new RelativeStrengthIndexFormulaInfo();
  77. case FinancialFormula.MovingAverageConvergenceDivergence:
  78. return new MovingAverageConvergenceDivergenceFormulaInfo();
  79. case FinancialFormula.CommodityChannelIndex:
  80. return new CommodityChannelIndexFormulaInfo();
  81. // Forecasting
  82. case FinancialFormula.Forecasting:
  83. return new ForecastingFormulaInfo();
  84. // Volume Indicators
  85. case FinancialFormula.MoneyFlow:
  86. return new MoneyFlowFormulaInfo();
  87. case FinancialFormula.PriceVolumeTrend:
  88. return new PriceVolumeTrendFormulaInfo();
  89. case FinancialFormula.OnBalanceVolume:
  90. return new OnBalanceVolumeFormulaInfo();
  91. case FinancialFormula.NegativeVolumeIndex:
  92. return new NegativeVolumeIndexFormulaInfo();
  93. case FinancialFormula.PositiveVolumeIndex:
  94. return new PositiveVolumeIndexFormulaInfo();
  95. case FinancialFormula.AccumulationDistribution:
  96. return new AccumulationDistributionFormulaInfo();
  97. default:
  98. Debug.Fail(String.Format(CultureInfo.InvariantCulture, "{0} case is not defined", formula));
  99. return null;
  100. }
  101. }
  102. /// <summary>
  103. /// Gets the data fields of the specified chart type.
  104. /// </summary>
  105. /// <param name="chartType">Type of the chart.</param>
  106. /// <returns>Data fields</returns>
  107. internal static IList<DataField> GetDataFields(SeriesChartType chartType)
  108. {
  109. switch (chartType)
  110. {
  111. case SeriesChartType.BoxPlot:
  112. return new DataField[] {
  113. DataField.LowerWisker, DataField.UpperWisker,
  114. DataField.LowerBox, DataField.UpperBox,
  115. DataField.Average, DataField.Median };
  116. case SeriesChartType.Bubble:
  117. return new DataField[] {
  118. DataField.Bubble, DataField.BubbleSize };
  119. case SeriesChartType.Candlestick:
  120. case SeriesChartType.Stock:
  121. return new DataField[] {
  122. DataField.High, DataField.Low,
  123. DataField.Open, DataField.Close };
  124. case SeriesChartType.ErrorBar:
  125. return new DataField[] {
  126. DataField.Center,
  127. DataField.LowerError, DataField.UpperError};
  128. case SeriesChartType.RangeBar:
  129. case SeriesChartType.Range:
  130. case SeriesChartType.RangeColumn:
  131. case SeriesChartType.SplineRange:
  132. return new DataField[] {
  133. DataField.Top, DataField.Bottom };
  134. default:
  135. return new DataField[] { DataField.Y };
  136. }
  137. }
  138. /// <summary>
  139. /// Gets the default type of the chart associated with this field name.
  140. /// </summary>
  141. /// <param name="field">The field.</param>
  142. /// <returns></returns>
  143. internal static SeriesChartType GetDefaultChartType(DataField field)
  144. {
  145. switch (field)
  146. {
  147. default:
  148. case DataField.Y:
  149. return SeriesChartType.Line;
  150. case DataField.LowerWisker:
  151. case DataField.UpperWisker:
  152. case DataField.LowerBox:
  153. case DataField.UpperBox:
  154. case DataField.Average:
  155. case DataField.Median:
  156. return SeriesChartType.BoxPlot;
  157. case DataField.Bubble:
  158. case DataField.BubbleSize:
  159. return SeriesChartType.Bubble;
  160. case DataField.High:
  161. case DataField.Low:
  162. case DataField.Open:
  163. case DataField.Close:
  164. return SeriesChartType.Stock;
  165. case DataField.Center:
  166. case DataField.LowerError:
  167. case DataField.UpperError:
  168. return SeriesChartType.ErrorBar;
  169. case DataField.Top:
  170. case DataField.Bottom:
  171. return SeriesChartType.Range;
  172. }
  173. }
  174. /// <summary>
  175. /// Maps formula data field to a chart type specific data field.
  176. /// </summary>
  177. /// <param name="chartType">Type of the chart.</param>
  178. /// <param name="formulaField">The formula field to be mapped.</param>
  179. /// <returns>The series field</returns>
  180. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  181. internal static DataField? MapFormulaDataField(SeriesChartType chartType, DataField formulaField)
  182. {
  183. switch (formulaField)
  184. {
  185. case DataField.Top:
  186. case DataField.High:
  187. switch (chartType)
  188. {
  189. default: return null;
  190. case SeriesChartType.BoxPlot: return DataField.UpperBox;
  191. case SeriesChartType.Candlestick:
  192. case SeriesChartType.Stock: return DataField.High;
  193. case SeriesChartType.ErrorBar: return DataField.UpperError;
  194. case SeriesChartType.RangeBar:
  195. case SeriesChartType.Range:
  196. case SeriesChartType.RangeColumn:
  197. case SeriesChartType.SplineRange: return DataField.Top;
  198. }
  199. case DataField.Bottom:
  200. case DataField.Low:
  201. switch (chartType)
  202. {
  203. default: return null;
  204. case SeriesChartType.BoxPlot: return DataField.LowerBox;
  205. case SeriesChartType.Candlestick:
  206. case SeriesChartType.Stock: return DataField.Low;
  207. case SeriesChartType.ErrorBar: return DataField.LowerError;
  208. case SeriesChartType.RangeBar:
  209. case SeriesChartType.Range:
  210. case SeriesChartType.RangeColumn:
  211. case SeriesChartType.SplineRange: return DataField.Bottom;
  212. }
  213. case DataField.Open:
  214. switch (chartType)
  215. {
  216. default: return null;
  217. case SeriesChartType.BoxPlot: return DataField.Average;
  218. case SeriesChartType.Candlestick:
  219. case SeriesChartType.Stock: return DataField.Open;
  220. case SeriesChartType.ErrorBar: return DataField.Center;
  221. case SeriesChartType.RangeBar:
  222. case SeriesChartType.Range:
  223. case SeriesChartType.RangeColumn:
  224. case SeriesChartType.SplineRange: return DataField.Bottom;
  225. }
  226. case DataField.Close:
  227. case DataField.Y:
  228. switch (chartType)
  229. {
  230. default: return DataField.Y;
  231. case SeriesChartType.BoxPlot: return DataField.Average;
  232. case SeriesChartType.Bubble: return DataField.Bubble;
  233. case SeriesChartType.Candlestick:
  234. case SeriesChartType.Stock: return DataField.Close;
  235. case SeriesChartType.ErrorBar: return DataField.Center;
  236. case SeriesChartType.RangeBar:
  237. case SeriesChartType.Range:
  238. case SeriesChartType.RangeColumn:
  239. case SeriesChartType.SplineRange: return DataField.Top;
  240. }
  241. default:
  242. return null;
  243. }
  244. }
  245. #endregion
  246. }
  247. #endregion
  248. #region class FormulaInfo and inherited FormulaSpecific classes
  249. /// <summary>
  250. /// This a base class of the formula metainfo classes.
  251. /// </summary>
  252. internal abstract class FormulaInfo
  253. {
  254. #region Fields
  255. DataField[] _inputFields;
  256. DataField[] _outputFields;
  257. object[] _parameters;
  258. #endregion
  259. #region Properties
  260. /// <summary>
  261. /// Gets the input data fields of the formula.
  262. /// </summary>
  263. /// <value>The input fields.</value>
  264. public DataField[] InputFields
  265. {
  266. get { return _inputFields; }
  267. }
  268. /// <summary>
  269. /// Gets the output data fields of the formula.
  270. /// </summary>
  271. /// <value>The output fields.</value>
  272. public DataField[] OutputFields
  273. {
  274. get { return _outputFields; }
  275. }
  276. /// <summary>
  277. /// Gets the parameters of the formula.
  278. /// </summary>
  279. /// <value>The parameters.</value>
  280. public object[] Parameters
  281. {
  282. get { return _parameters; }
  283. }
  284. #endregion
  285. #region Constructors
  286. /// <summary>
  287. /// Initializes a new instance of the <see cref="FormulaInfo"/> class.
  288. /// </summary>
  289. /// <param name="inputFields">The input data fields.</param>
  290. /// <param name="outputFields">The output data fields.</param>
  291. /// <param name="defaultParams">The default formula params.</param>
  292. public FormulaInfo(DataField[] inputFields, DataField[] outputFields, params object[] defaultParams)
  293. {
  294. _inputFields = inputFields;
  295. _outputFields = outputFields;
  296. _parameters = defaultParams;
  297. }
  298. #endregion
  299. #region Methods
  300. /// <summary>
  301. /// Saves the formula parameters to a string.
  302. /// </summary>
  303. /// <returns>Csv string with parameters</returns>
  304. internal virtual string SaveParametersToString()
  305. {
  306. StringBuilder sb = new StringBuilder();
  307. for (int i = 0; i < _parameters.Length; i++)
  308. {
  309. if (i > 0) sb.Append(',');
  310. sb.AppendFormat(CultureInfo.InvariantCulture, "{0}", _parameters[i]);
  311. }
  312. return sb.ToString();
  313. }
  314. /// <summary>
  315. /// Loads the formula parameters from string.
  316. /// </summary>
  317. /// <param name="parameters">Csv string with parameters.</param>
  318. internal virtual void LoadParametersFromString(string parameters)
  319. {
  320. if (String.IsNullOrEmpty(parameters))
  321. return;
  322. string[] paramStringList = parameters.Split(',');
  323. int paramStringIndex = 0;
  324. for (int i = 0; i < _parameters.Length && paramStringIndex < paramStringList.Length; i++)
  325. {
  326. string newParamValue = paramStringList[paramStringIndex++];
  327. if (!String.IsNullOrEmpty(newParamValue))
  328. {
  329. _parameters[i] = ParseParameter(i, newParamValue);
  330. }
  331. }
  332. }
  333. /// <summary>
  334. /// Parses the formula parameter.
  335. /// </summary>
  336. /// <param name="index">The param index.</param>
  337. /// <param name="newParamValue">The parameter value string.</param>
  338. /// <returns>Parameter value.</returns>
  339. internal virtual object ParseParameter(int index, string newParamValue)
  340. {
  341. object param = _parameters[index];
  342. if (param is int)
  343. {
  344. return Convert.ToInt32(newParamValue, CultureInfo.InvariantCulture);
  345. }
  346. else if (param is bool)
  347. {
  348. return Convert.ToBoolean(newParamValue, CultureInfo.InvariantCulture);
  349. }
  350. else if (param is double)
  351. {
  352. return Convert.ToDouble(newParamValue, CultureInfo.InvariantCulture);
  353. }
  354. return null;
  355. }
  356. /// <summary>
  357. /// Checks the formula parameter string.
  358. /// </summary>
  359. /// <param name="parameters">The parameters.</param>
  360. internal virtual void CheckParameterString(string parameters)
  361. {
  362. if (String.IsNullOrEmpty(parameters))
  363. return;
  364. string[] paramStringList = parameters.Split(',');
  365. int paramStringIndex = 0;
  366. for (int i = 0; i < _parameters.Length && paramStringIndex < paramStringList.Length; i++)
  367. {
  368. string newParamValue = paramStringList[paramStringIndex++];
  369. if (!String.IsNullOrEmpty(newParamValue))
  370. {
  371. try
  372. {
  373. ParseParameter(i, newParamValue);
  374. }
  375. catch (FormatException)
  376. {
  377. throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(parameters));
  378. }
  379. }
  380. }
  381. }
  382. #endregion
  383. }
  384. /// <summary>
  385. /// MovingAverage FormulaInfo
  386. /// </summary>
  387. internal class MovingAverageFormulaInfo : FormulaInfo
  388. {
  389. //Constructor
  390. /// <summary>
  391. /// Initializes a new instance of the <see cref="MovingAverageFormulaInfo"/> class.
  392. /// </summary>
  393. public MovingAverageFormulaInfo()
  394. : this(2, false) //Defaults
  395. {
  396. }
  397. /// <summary>
  398. /// Initializes a new instance of the <see cref="MovingAverageFormulaInfo"/> class.
  399. /// </summary>
  400. /// <param name="period">The period.</param>
  401. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  402. public MovingAverageFormulaInfo(int period, bool startFromFirst)
  403. : base(
  404. new DataField[] { DataField.Y }, //Input fields
  405. new DataField[] { DataField.Y }, //Output fields
  406. period, startFromFirst)
  407. {
  408. }
  409. }
  410. /// <summary>
  411. /// ExponentialMoving AverageFormulaInfo
  412. /// </summary>
  413. internal class ExponentialMovingAverageFormulaInfo : FormulaInfo
  414. {
  415. //Constructor
  416. /// <summary>
  417. /// Initializes a new instance of the <see cref="ExponentialMovingAverageFormulaInfo"/> class.
  418. /// </summary>
  419. public ExponentialMovingAverageFormulaInfo()
  420. : this(2, false) //Defaults
  421. {
  422. }
  423. /// <summary>
  424. /// Initializes a new instance of the <see cref="ExponentialMovingAverageFormulaInfo"/> class.
  425. /// </summary>
  426. /// <param name="period">The period.</param>
  427. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  428. public ExponentialMovingAverageFormulaInfo(int period, bool startFromFirst)
  429. : base(
  430. new DataField[] { DataField.Y }, //Input fields
  431. new DataField[] { DataField.Y }, //Output fields
  432. period, startFromFirst)
  433. {
  434. }
  435. }
  436. /// <summary>
  437. /// WeightedMovingAverageFormulaInfo
  438. /// </summary>
  439. internal class WeightedMovingAverageFormulaInfo : FormulaInfo
  440. {
  441. //Constructor
  442. /// <summary>
  443. /// Initializes a new instance of the <see cref="WeightedMovingAverageFormulaInfo"/> class.
  444. /// </summary>
  445. public WeightedMovingAverageFormulaInfo()
  446. : this(2, false) //Defaults
  447. {
  448. }
  449. /// <summary>
  450. /// Initializes a new instance of the <see cref="WeightedMovingAverageFormulaInfo"/> class.
  451. /// </summary>
  452. /// <param name="period">The period.</param>
  453. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  454. public WeightedMovingAverageFormulaInfo(int period, bool startFromFirst)
  455. : base(
  456. new DataField[] { DataField.Y }, //Input fields
  457. new DataField[] { DataField.Y }, //Output fields
  458. period, startFromFirst)
  459. {
  460. }
  461. }
  462. /// <summary>
  463. /// TriangularMovingAverage FormulaInfo
  464. /// </summary>
  465. internal class TriangularMovingAverageFormulaInfo : FormulaInfo
  466. {
  467. //Constructor
  468. /// <summary>
  469. /// Initializes a new instance of the <see cref="TriangularMovingAverageFormulaInfo"/> class.
  470. /// </summary>
  471. public TriangularMovingAverageFormulaInfo()
  472. : this(2, false) //Defaults
  473. {
  474. }
  475. /// <summary>
  476. /// Initializes a new instance of the <see cref="TriangularMovingAverageFormulaInfo"/> class.
  477. /// </summary>
  478. /// <param name="period">The period.</param>
  479. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  480. public TriangularMovingAverageFormulaInfo(int period, bool startFromFirst)
  481. : base(
  482. new DataField[] { DataField.Y }, //Input fields
  483. new DataField[] { DataField.Y }, //Output fields
  484. period, startFromFirst)
  485. {
  486. }
  487. }
  488. /// <summary>
  489. /// TripleExponentialMovingAverage FormulaInfo
  490. /// </summary>
  491. internal class TripleExponentialMovingAverageFormulaInfo : FormulaInfo
  492. {
  493. //Constructor
  494. /// <summary>
  495. /// Initializes a new instance of the <see cref="TripleExponentialMovingAverageFormulaInfo"/> class.
  496. /// </summary>
  497. public TripleExponentialMovingAverageFormulaInfo()
  498. : this(12) //Defaults
  499. {
  500. }
  501. /// <summary>
  502. /// Initializes a new instance of the <see cref="TripleExponentialMovingAverageFormulaInfo"/> class.
  503. /// </summary>
  504. /// <param name="period">The period.</param>
  505. public TripleExponentialMovingAverageFormulaInfo(int period)
  506. : base(
  507. new DataField[] { DataField.Y }, //Input fields
  508. new DataField[] { DataField.Y }, //Output fields
  509. period)
  510. {
  511. }
  512. }
  513. /// <summary>
  514. /// BollingerBands FormulaInfo
  515. /// </summary>
  516. internal class BollingerBandsFormulaInfo : FormulaInfo
  517. {
  518. //Constructor
  519. /// <summary>
  520. /// Initializes a new instance of the <see cref="BollingerBandsFormulaInfo"/> class.
  521. /// </summary>
  522. public BollingerBandsFormulaInfo()
  523. : this(3, 2, true) //Defaults
  524. {
  525. }
  526. /// <summary>
  527. /// Initializes a new instance of the <see cref="BollingerBandsFormulaInfo"/> class.
  528. /// </summary>
  529. /// <param name="period">The period.</param>
  530. /// <param name="deviation">The deviation.</param>
  531. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  532. public BollingerBandsFormulaInfo(int period, double deviation, bool startFromFirst)
  533. : base(
  534. new DataField[] { DataField.Y }, //Input fields
  535. new DataField[] { DataField.Top, DataField.Bottom }, //Output fields
  536. period, deviation, startFromFirst)
  537. {
  538. }
  539. }
  540. /// <summary>
  541. /// TypicalPrice FormulaInfo
  542. /// </summary>
  543. internal class TypicalPriceFormulaInfo : FormulaInfo
  544. {
  545. //Constructor
  546. /// <summary>
  547. /// Initializes a new instance of the <see cref="TypicalPriceFormulaInfo"/> class.
  548. /// </summary>
  549. public TypicalPriceFormulaInfo()
  550. : base(
  551. new DataField[] { DataField.Close, DataField.High, DataField.Low }, //Input fields
  552. new DataField[] { DataField.Y }) //Output fields
  553. {
  554. }
  555. }
  556. /// <summary>
  557. /// WeightedClose FormulaInfo
  558. /// </summary>
  559. internal class WeightedCloseFormulaInfo : FormulaInfo
  560. {
  561. //Constructor
  562. /// <summary>
  563. /// Initializes a new instance of the <see cref="WeightedCloseFormulaInfo"/> class.
  564. /// </summary>
  565. public WeightedCloseFormulaInfo()
  566. : base(
  567. new DataField[] { DataField.Close, DataField.High, DataField.Low }, //Input fields
  568. new DataField[] { DataField.Y }) //Output fields
  569. {
  570. }
  571. }
  572. /// <summary>
  573. /// MedianPrice FormulaInfo
  574. /// </summary>
  575. internal class MedianPriceFormulaInfo : FormulaInfo
  576. {
  577. //Constructor
  578. /// <summary>
  579. /// Initializes a new instance of the <see cref="MedianPriceFormulaInfo"/> class.
  580. /// </summary>
  581. public MedianPriceFormulaInfo()
  582. : base(
  583. new DataField[] { DataField.High, DataField.Low }, //Input fields
  584. new DataField[] { DataField.Y }) //Output fields
  585. {
  586. }
  587. }
  588. /// <summary>
  589. /// Envelopes FormulaInfo
  590. /// </summary>
  591. internal class EnvelopesFormulaInfo : FormulaInfo
  592. {
  593. //Constructor
  594. /// <summary>
  595. /// Initializes a new instance of the <see cref="EnvelopesFormulaInfo"/> class.
  596. /// </summary>
  597. public EnvelopesFormulaInfo()
  598. : this(2, 10, true) //Defaults
  599. {
  600. }
  601. /// <summary>
  602. /// Initializes a new instance of the <see cref="EnvelopesFormulaInfo"/> class.
  603. /// </summary>
  604. /// <param name="period">The period.</param>
  605. /// <param name="shiftPercentage">The shift percentage.</param>
  606. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  607. public EnvelopesFormulaInfo(int period, double shiftPercentage, bool startFromFirst)
  608. : base(
  609. new DataField[] { DataField.Y }, //Input fields
  610. new DataField[] { DataField.Top, DataField.Bottom }, //Output fields
  611. period, shiftPercentage, startFromFirst)
  612. {
  613. }
  614. }
  615. /// <summary>
  616. /// StandardDeviation FormulaInfo
  617. /// </summary>
  618. internal class StandardDeviationFormulaInfo : FormulaInfo
  619. {
  620. //Constructor
  621. /// <summary>
  622. /// Initializes a new instance of the <see cref="StandardDeviationFormulaInfo"/> class.
  623. /// </summary>
  624. public StandardDeviationFormulaInfo()
  625. : this(2, false) //Defaults
  626. {
  627. }
  628. /// <summary>
  629. /// Initializes a new instance of the <see cref="StandardDeviationFormulaInfo"/> class.
  630. /// </summary>
  631. /// <param name="period">The period.</param>
  632. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  633. public StandardDeviationFormulaInfo(int period, bool startFromFirst)
  634. : base(
  635. new DataField[] { DataField.Y }, //Input fields
  636. new DataField[] { DataField.Y }, //Output fields
  637. period, startFromFirst)
  638. {
  639. }
  640. }
  641. /// <summary>
  642. /// ChaikinOscillatorFormulaInfo
  643. /// </summary>
  644. internal class ChaikinOscillatorFormulaInfo : FormulaInfo
  645. {
  646. //Constructor
  647. /// <summary>
  648. /// Initializes a new instance of the <see cref="ChaikinOscillatorFormulaInfo"/> class.
  649. /// </summary>
  650. public ChaikinOscillatorFormulaInfo()
  651. : this(3, 10, false) //Defaults
  652. {
  653. }
  654. /// <summary>
  655. /// Initializes a new instance of the <see cref="ChaikinOscillatorFormulaInfo"/> class.
  656. /// </summary>
  657. /// <param name="shortPeriod">The short period.</param>
  658. /// <param name="longPeriod">The long period.</param>
  659. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  660. public ChaikinOscillatorFormulaInfo(int shortPeriod, int longPeriod, bool startFromFirst)
  661. : base(
  662. new DataField[] { DataField.High, DataField.Low, DataField.Close, DataField.Y }, //Input fields
  663. new DataField[] { DataField.Y }, //Output fields
  664. shortPeriod, longPeriod, startFromFirst)
  665. {
  666. }
  667. }
  668. /// <summary>
  669. /// DetrendedPriceOscillator FormulaInfo
  670. /// </summary>
  671. internal class DetrendedPriceOscillatorFormulaInfo : FormulaInfo
  672. {
  673. //Constructor
  674. /// <summary>
  675. /// Initializes a new instance of the <see cref="DetrendedPriceOscillatorFormulaInfo"/> class.
  676. /// </summary>
  677. public DetrendedPriceOscillatorFormulaInfo()
  678. : this(2, false) //Defaults
  679. {
  680. }
  681. /// <summary>
  682. /// Initializes a new instance of the <see cref="DetrendedPriceOscillatorFormulaInfo"/> class.
  683. /// </summary>
  684. /// <param name="period">The period.</param>
  685. /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
  686. public DetrendedPriceOscillatorFormulaInfo(int period, bool startFromFirst)
  687. : base(
  688. new DataField[] { DataField.Y }, //Input fields
  689. new DataField[] { DataField.Y }, //Output fields
  690. period, startFromFirst)
  691. {
  692. }
  693. }
  694. /// <summary>
  695. /// VolatilityChaikins FormulaInfo
  696. /// </summary>
  697. internal class VolatilityChaikinsFormulaInfo : FormulaInfo
  698. {
  699. //Constructor
  700. /// <summary>
  701. /// Initializes a new instance of the <see cref="VolatilityChaikinsFormulaInfo"/> class.
  702. /// </summary>
  703. public VolatilityChaikinsFormulaInfo()
  704. : this(10, 10) //Defaults
  705. {
  706. }
  707. /// <summary>
  708. /// Initializes a new instance of the <see cref="VolatilityChaikinsFormulaInfo"/> class.
  709. /// </summary>
  710. /// <param name="period">The period.</param>
  711. /// <param name="signalPeriod">The signal period.</param>
  712. public VolatilityChaikinsFormulaInfo(int period, int signalPeriod)
  713. : base(
  714. new DataField[] { DataField.High, DataField.Low }, //Input fields
  715. new DataField[] { DataField.Y }, //Output fields
  716. period, signalPeriod)
  717. {
  718. }
  719. }
  720. /// <summary>
  721. /// VolumeOscillator FormulaInfo
  722. /// </summary>
  723. internal class VolumeOscillatorFormulaInfo : FormulaInfo
  724. {
  725. //Constructor
  726. /// <summary>
  727. /// Initializes a new instance of the <see cref="VolumeOscillatorFormulaInfo"/> class.
  728. /// </summary>
  729. public VolumeOscillatorFormulaInfo()
  730. : this(5, 10, true) //Defaults
  731. {
  732. }
  733. /// <summary>
  734. /// Initializes a new instance of the <see cref="VolumeOscillatorFormulaInfo"/> class.
  735. /// </summary>
  736. /// <param name="shortPeriod">The short period.</param>
  737. /// <param name="longPeriod">The long period.</param>
  738. /// <param name="percentage">if set to <c>true</c> [percentage].</param>
  739. public VolumeOscillatorFormulaInfo(int shortPeriod, int longPeriod, bool percentage)
  740. : base(
  741. new DataField[] { DataField.Y }, //Input fields
  742. new DataField[] { DataField.Y }, //Output fields
  743. shortPeriod, longPeriod, percentage)
  744. {
  745. }
  746. }
  747. /// <summary>
  748. /// StochasticIndicatorFormulaInfo
  749. /// </summary>
  750. internal class StochasticIndicatorFormulaInfo : FormulaInfo
  751. {
  752. //Constructor
  753. /// <summary>
  754. /// Initializes a new instance of the <see cref="StochasticIndicatorFormulaInfo"/> class.
  755. /// </summary>
  756. public StochasticIndicatorFormulaInfo()
  757. : this(10, 10) //Defaults
  758. {
  759. }
  760. /// <summary>
  761. /// Initializes a new instance of the <see cref="StochasticIndicatorFormulaInfo"/> class.
  762. /// </summary>
  763. /// <param name="periodD">The period D.</param>
  764. /// <param name="periodK">The period K.</param>
  765. public StochasticIndicatorFormulaInfo(int periodD, int periodK)
  766. : base(
  767. new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
  768. new DataField[] { DataField.Y, DataField.Y }, //Output fields
  769. periodD, periodK)
  770. {
  771. }
  772. }
  773. /// <summary>
  774. /// WilliamsRFormulaInfo
  775. /// </summary>
  776. internal class WilliamsRFormulaInfo : FormulaInfo
  777. {
  778. //Constructor
  779. /// <summary>
  780. /// Initializes a new instance of the <see cref="WilliamsRFormulaInfo"/> class.
  781. /// </summary>
  782. public WilliamsRFormulaInfo()
  783. : this(14) //Defaults
  784. {
  785. }
  786. /// <summary>
  787. /// Initializes a new instance of the <see cref="WilliamsRFormulaInfo"/> class.
  788. /// </summary>
  789. /// <param name="period">The period.</param>
  790. public WilliamsRFormulaInfo(int period)
  791. : base(
  792. new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
  793. new DataField[] { DataField.Y }, //Output fields
  794. period)
  795. {
  796. }
  797. }
  798. /// <summary>
  799. /// AverageTrueRange FormulaInfo
  800. /// </summary>
  801. internal class AverageTrueRangeFormulaInfo : FormulaInfo
  802. {
  803. //Constructor
  804. /// <summary>
  805. /// Initializes a new instance of the <see cref="AverageTrueRangeFormulaInfo"/> class.
  806. /// </summary>
  807. public AverageTrueRangeFormulaInfo()
  808. : this(14) //Defaults
  809. {
  810. }
  811. /// <summary>
  812. /// Initializes a new instance of the <see cref="AverageTrueRangeFormulaInfo"/> class.
  813. /// </summary>
  814. /// <param name="period">The period.</param>
  815. public AverageTrueRangeFormulaInfo(int period)
  816. : base(
  817. new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
  818. new DataField[] { DataField.Y }, //Output fields
  819. period)
  820. {
  821. }
  822. }
  823. /// <summary>
  824. /// EaseOfMovement FormulaInfo
  825. /// </summary>
  826. internal class EaseOfMovementFormulaInfo : FormulaInfo
  827. {
  828. //Constructor
  829. /// <summary>
  830. /// Initializes a new instance of the <see cref="EaseOfMovementFormulaInfo"/> class.
  831. /// </summary>
  832. public EaseOfMovementFormulaInfo()
  833. : base(
  834. new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
  835. new DataField[] { DataField.Y }) //Output fields
  836. {
  837. }
  838. }
  839. /// <summary>
  840. /// MassIndex FormulaInfo
  841. /// </summary>
  842. internal class MassIndexFormulaInfo : FormulaInfo
  843. {
  844. //Constructor
  845. /// <summary>
  846. /// Initializes a new instance of the <see cref="MassIndexFormulaInfo"/> class.
  847. /// </summary>
  848. public MassIndexFormulaInfo()
  849. : this(25, 9) //Defaults
  850. {
  851. }
  852. /// <summary>
  853. /// Initializes a new instance of the <see cref="MassIndexFormulaInfo"/> class.
  854. /// </summary>
  855. /// <param name="period">The period.</param>
  856. /// <param name="averagePeriod">The average period.</param>
  857. public MassIndexFormulaInfo(int period, int averagePeriod)
  858. : base(
  859. new DataField[] { DataField.High, DataField.Low }, //Input fields
  860. new DataField[] { DataField.Y }, //Output fields
  861. period, averagePeriod)
  862. {
  863. }
  864. }
  865. /// <summary>
  866. /// Performance FormulaInfo
  867. /// </summary>
  868. internal class PerformanceFormulaInfo : FormulaInfo
  869. {
  870. //Constructor
  871. /// <summary>
  872. /// Initializes a new instance of the <see cref="PerformanceFormulaInfo"/> class.
  873. /// </summary>
  874. public PerformanceFormulaInfo()
  875. : base(
  876. new DataField[] { DataField.Close }, //Input fields
  877. new DataField[] { DataField.Y }) //Output fields
  878. {
  879. }
  880. }
  881. /// <summary>
  882. /// RateOfChange FormulaInfo
  883. /// </summary>
  884. internal class RateOfChangeFormulaInfo : FormulaInfo
  885. {
  886. //Constructor
  887. /// <summary>
  888. /// Initializes a new instance of the <see cref="RateOfChangeFormulaInfo"/> class.
  889. /// </summary>
  890. public RateOfChangeFormulaInfo()
  891. : this(10) //Defaults
  892. {
  893. }
  894. /// <summary>
  895. /// Initializes a new instance of the <see cref="RateOfChangeFormulaInfo"/> class.
  896. /// </summary>
  897. /// <param name="period">The period.</param>
  898. public RateOfChangeFormulaInfo(int period)
  899. : base(
  900. new DataField[] { DataField.Close }, //Input fields
  901. new DataField[] { DataField.Y }, //Output fields
  902. period)
  903. {
  904. }
  905. }
  906. /// <summary>
  907. /// RelativeStrengthIndex FormulaInfo
  908. /// </summary>
  909. internal class RelativeStrengthIndexFormulaInfo : FormulaInfo
  910. {
  911. //Constructor
  912. /// <summary>
  913. /// Initializes a new instance of the <see cref="RelativeStrengthIndexFormulaInfo"/> class.
  914. /// </summary>
  915. public RelativeStrengthIndexFormulaInfo()
  916. : this(10) //Defaults
  917. {
  918. }
  919. /// <summary>
  920. /// Initializes a new instance of the <see cref="RelativeStrengthIndexFormulaInfo"/> class.
  921. /// </summary>
  922. /// <param name="period">The period.</param>
  923. public RelativeStrengthIndexFormulaInfo(int period)
  924. : base(
  925. new DataField[] { DataField.Close }, //Input fields
  926. new DataField[] { DataField.Y }, //Output fields
  927. period)
  928. {
  929. }
  930. }
  931. /// <summary>
  932. /// MovingAverageConvergenceDivergence FormulaInfo
  933. /// </summary>
  934. internal class MovingAverageConvergenceDivergenceFormulaInfo : FormulaInfo
  935. {
  936. //Constructor
  937. /// <summary>
  938. /// Initializes a new instance of the <see cref="MovingAverageConvergenceDivergenceFormulaInfo"/> class.
  939. /// </summary>
  940. public MovingAverageConvergenceDivergenceFormulaInfo()
  941. : this(12, 26) //Defaults
  942. {
  943. }
  944. /// <summary>
  945. /// Initializes a new instance of the <see cref="MovingAverageConvergenceDivergenceFormulaInfo"/> class.
  946. /// </summary>
  947. /// <param name="shortPeriod">The short period.</param>
  948. /// <param name="longPeriod">The long period.</param>
  949. public MovingAverageConvergenceDivergenceFormulaInfo(int shortPeriod, int longPeriod)
  950. : base(
  951. new DataField[] { DataField.Close }, //Input fields
  952. new DataField[] { DataField.Y }, //Output fields
  953. shortPeriod, longPeriod)
  954. {
  955. }
  956. }
  957. /// <summary>
  958. /// CommodityChannelIndex FormulaInfo
  959. /// </summary>
  960. internal class CommodityChannelIndexFormulaInfo : FormulaInfo
  961. {
  962. //Constructor
  963. /// <summary>
  964. /// Initializes a new instance of the <see cref="CommodityChannelIndexFormulaInfo"/> class.
  965. /// </summary>
  966. public CommodityChannelIndexFormulaInfo()
  967. : this(10) //Defaults
  968. {
  969. }
  970. /// <summary>
  971. /// Initializes a new instance of the <see cref="CommodityChannelIndexFormulaInfo"/> class.
  972. /// </summary>
  973. /// <param name="period">The period.</param>
  974. public CommodityChannelIndexFormulaInfo(int period)
  975. : base(
  976. new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
  977. new DataField[] { DataField.Y }, //Output fields
  978. period)
  979. {
  980. }
  981. }
  982. /// <summary>
  983. /// Forecasting FormulaInfo
  984. /// </summary>
  985. internal class ForecastingFormulaInfo : FormulaInfo
  986. {
  987. //Fields
  988. string _parameters;
  989. //Constructor
  990. /// <summary>
  991. /// Initializes a new instance of the <see cref="ForecastingFormulaInfo"/> class.
  992. /// </summary>
  993. public ForecastingFormulaInfo()
  994. : this(TimeSeriesAndForecasting.RegressionType.Polynomial, 2, 0, true, true) //Defaults
  995. {
  996. }
  997. /// <summary>
  998. /// Initializes a new instance of the <see cref="ForecastingFormulaInfo"/> class.
  999. /// </summary>
  1000. /// <param name="regressionType">Type of the regression.</param>
  1001. /// <param name="polynomialDegree">The polynomial degree.</param>
  1002. /// <param name="forecastingPeriod">The forecasting period.</param>
  1003. /// <param name="returnApproximationError">if set to <c>true</c> [return approximation error].</param>
  1004. /// <param name="returnForecastingError">if set to <c>true</c> [return forecasting error].</param>
  1005. public ForecastingFormulaInfo(TimeSeriesAndForecasting.RegressionType regressionType, int polynomialDegree, int forecastingPeriod, bool returnApproximationError, bool returnForecastingError)
  1006. : base(
  1007. new DataField[] { DataField.Close }, //Input fields
  1008. new DataField[] { DataField.Close, DataField.High, DataField.Low }, //Output fields
  1009. regressionType, polynomialDegree, forecastingPeriod, returnApproximationError, returnForecastingError)
  1010. {
  1011. }
  1012. //Methods
  1013. /// <summary>
  1014. /// Loads the formula parameters from string.
  1015. /// </summary>
  1016. /// <param name="parameters">Csv string with parameters.</param>
  1017. internal override void LoadParametersFromString(string parameters)
  1018. {
  1019. _parameters = parameters;
  1020. }
  1021. /// <summary>
  1022. /// Checks the formula parameter string.
  1023. /// </summary>
  1024. /// <param name="parameters">The parameters.</param>
  1025. internal override void CheckParameterString(string parameters)
  1026. {
  1027. if (String.IsNullOrEmpty(parameters))
  1028. return;
  1029. string[] paramStringList = parameters.Split(',');
  1030. int paramStringIndex = 1;
  1031. //Don't check the first param
  1032. for (int i = 2; i < Parameters.Length && paramStringIndex < paramStringList.Length; i++)
  1033. {
  1034. string newParamValue = paramStringList[paramStringIndex++];
  1035. if (!String.IsNullOrEmpty(newParamValue))
  1036. {
  1037. try
  1038. {
  1039. ParseParameter(i, newParamValue);
  1040. }
  1041. catch (FormatException)
  1042. {
  1043. throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(parameters));
  1044. }
  1045. }
  1046. }
  1047. }
  1048. /// <summary>
  1049. /// Saves the formula parameters to a string.
  1050. /// </summary>
  1051. /// <returns>Csv string with parameters</returns>
  1052. internal override string SaveParametersToString()
  1053. {
  1054. if (String.IsNullOrEmpty(_parameters))
  1055. return _parameters;
  1056. else
  1057. return "2,0,true,true";
  1058. }
  1059. }
  1060. /// <summary>
  1061. /// MoneyFlow FormulaInfo
  1062. /// </summary>
  1063. internal class MoneyFlowFormulaInfo : FormulaInfo
  1064. {
  1065. //Constructor
  1066. /// <summary>
  1067. /// Initializes a new instance of the <see cref="MoneyFlowFormulaInfo"/> class.
  1068. /// </summary>
  1069. public MoneyFlowFormulaInfo()
  1070. : this(2) //Defaults
  1071. {
  1072. }
  1073. /// <summary>
  1074. /// Initializes a new instance of the <see cref="MoneyFlowFormulaInfo"/> class.
  1075. /// </summary>
  1076. /// <param name="period">The period.</param>
  1077. public MoneyFlowFormulaInfo(int period)
  1078. : base(
  1079. new DataField[] { DataField.High, DataField.Low, DataField.Close, DataField.Y }, //Input fields: High,Low,Close,Volume
  1080. new DataField[] { DataField.Y }, //Output fields
  1081. period)
  1082. {
  1083. }
  1084. }
  1085. /// <summary>
  1086. /// PriceVolumeTrend FormulaInfo
  1087. /// </summary>
  1088. internal class PriceVolumeTrendFormulaInfo : FormulaInfo
  1089. {
  1090. //Constructor
  1091. /// <summary>
  1092. /// Initializes a new instance of the <see cref="PriceVolumeTrendFormulaInfo"/> class.
  1093. /// </summary>
  1094. public PriceVolumeTrendFormulaInfo()
  1095. : base(
  1096. new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
  1097. new DataField[] { DataField.Y }) //Output fields
  1098. {
  1099. }
  1100. }
  1101. /// <summary>
  1102. /// OnBalanceVolume FormulaInfo
  1103. /// </summary>
  1104. internal class OnBalanceVolumeFormulaInfo : FormulaInfo
  1105. {
  1106. //Constructor
  1107. /// <summary>
  1108. /// Initializes a new instance of the <see cref="OnBalanceVolumeFormulaInfo"/> class.
  1109. /// </summary>
  1110. public OnBalanceVolumeFormulaInfo()
  1111. : base(
  1112. new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
  1113. new DataField[] { DataField.Y }) //Output fields
  1114. {
  1115. }
  1116. }
  1117. /// <summary>
  1118. /// NegativeVolumeIndex FormulaInfo
  1119. /// </summary>
  1120. internal class NegativeVolumeIndexFormulaInfo : FormulaInfo
  1121. {
  1122. //Constructor
  1123. /// <summary>
  1124. /// Initializes a new instance of the <see cref="NegativeVolumeIndexFormulaInfo"/> class.
  1125. /// </summary>
  1126. public NegativeVolumeIndexFormulaInfo() //Note about parameters: Start value is mandatory so we don't provide the default
  1127. : this(double.NaN)
  1128. {
  1129. }
  1130. /// <summary>
  1131. /// Initializes a new instance of the <see cref="NegativeVolumeIndexFormulaInfo"/> class.
  1132. /// </summary>
  1133. /// <param name="startValue">The start value.</param>
  1134. public NegativeVolumeIndexFormulaInfo(double startValue)
  1135. : base(
  1136. new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
  1137. new DataField[] { DataField.Y },
  1138. startValue) //Output fields
  1139. {
  1140. }
  1141. }
  1142. /// <summary>
  1143. /// PositiveVolumeIndex FormulaInfo
  1144. /// </summary>
  1145. internal class PositiveVolumeIndexFormulaInfo : FormulaInfo
  1146. {
  1147. //Constructor
  1148. /// <summary>
  1149. /// Initializes a new instance of the <see cref="PositiveVolumeIndexFormulaInfo"/> class.
  1150. /// </summary>
  1151. public PositiveVolumeIndexFormulaInfo() //Note about parameters: Start value is mandatory so we don't provide the default
  1152. : this(double.NaN)
  1153. {
  1154. }
  1155. /// <summary>
  1156. /// Initializes a new instance of the <see cref="PositiveVolumeIndexFormulaInfo"/> class.
  1157. /// </summary>
  1158. /// <param name="startValue">The start value.</param>
  1159. public PositiveVolumeIndexFormulaInfo(double startValue)
  1160. : base(
  1161. new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
  1162. new DataField[] { DataField.Y },
  1163. startValue) //Output fields
  1164. {
  1165. }
  1166. }
  1167. /// <summary>
  1168. /// AccumulationDistribution FormulaInfo
  1169. /// </summary>
  1170. internal class AccumulationDistributionFormulaInfo : FormulaInfo
  1171. {
  1172. //Constructor
  1173. /// <summary>
  1174. /// Initializes a new instance of the <see cref="AccumulationDistributionFormulaInfo"/> class.
  1175. /// </summary>
  1176. public AccumulationDistributionFormulaInfo() //Note about parameters: Start value is mandatory so we don't provide the default
  1177. : base(
  1178. new DataField[] { DataField.High, DataField.Low, DataField.Close, DataField.Y }, //Input=High, Low, Close, Volume
  1179. new DataField[] { DataField.Y }) //Output fields
  1180. {
  1181. }
  1182. }
  1183. #endregion
  1184. #region enum DataField
  1185. /// <summary>
  1186. /// Chart data fields
  1187. /// </summary>
  1188. internal enum DataField
  1189. {
  1190. X,
  1191. Y,
  1192. LowerWisker,
  1193. UpperWisker,
  1194. LowerBox,
  1195. UpperBox,
  1196. Average,
  1197. Median,
  1198. Bubble,
  1199. BubbleSize,
  1200. High,
  1201. Low,
  1202. Open,
  1203. Close,
  1204. Center,
  1205. LowerError,
  1206. UpperError,
  1207. Top,
  1208. Bottom
  1209. }
  1210. #endregion
  1211. #region class SeriesFieldInfo
  1212. /// <summary>
  1213. /// SeriesFieldInfo class is a OO representation formula input/output data params ("Series1:Y2")
  1214. /// </summary>
  1215. internal class SeriesFieldInfo
  1216. {
  1217. #region Fields
  1218. private Series _series;
  1219. private string _seriesName;
  1220. private DataField _dataField;
  1221. #endregion
  1222. #region Properties
  1223. /// <summary>
  1224. /// Gets the series.
  1225. /// </summary>
  1226. /// <value>The series.</value>
  1227. public Series Series
  1228. {
  1229. get { return _series; }
  1230. }
  1231. /// <summary>
  1232. /// Gets the name of the series.
  1233. /// </summary>
  1234. /// <value>The name of the series.</value>
  1235. public string SeriesName
  1236. {
  1237. get { return _series != null ? _series.Name : _seriesName; }
  1238. }
  1239. /// <summary>
  1240. /// Gets the data field.
  1241. /// </summary>
  1242. /// <value>The data field.</value>
  1243. public DataField DataField
  1244. {
  1245. get { return _dataField; }
  1246. }
  1247. #endregion
  1248. #region Constructors
  1249. /// <summary>
  1250. /// Initializes a new instance of the <see cref="SeriesFieldInfo"/> class.
  1251. /// </summary>
  1252. /// <param name="series">The series.</param>
  1253. /// <param name="dataField">The data field.</param>
  1254. public SeriesFieldInfo(Series series, DataField dataField)
  1255. {
  1256. _series = series;
  1257. _dataField = dataField;
  1258. }
  1259. /// <summary>
  1260. /// Initializes a new instance of the <see cref="SeriesFieldInfo"/> class.
  1261. /// </summary>
  1262. /// <param name="seriesName">Name of the series.</param>
  1263. /// <param name="dataField">The data field.</param>
  1264. public SeriesFieldInfo(string seriesName, DataField dataField)
  1265. {
  1266. _seriesName = seriesName;
  1267. _dataField = dataField;
  1268. }
  1269. #endregion
  1270. }
  1271. #endregion
  1272. #region class SeriesFieldList
  1273. /// <summary>
  1274. /// SeriesFieldInfo class is a OO representation formula input/output data params ("Series1:Y2,Series2.Y4")
  1275. /// </summary>
  1276. internal class SeriesFieldList : List<SeriesFieldInfo>
  1277. {
  1278. /// <summary>
  1279. /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
  1280. /// </summary>
  1281. /// <returns>
  1282. /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
  1283. /// </returns>
  1284. public override string ToString()
  1285. {
  1286. StringBuilder sb = new StringBuilder();
  1287. for (int i = 0; i < this.Count; i++)
  1288. {
  1289. SeriesFieldInfo info = this[i];
  1290. if (i > 0)
  1291. sb.Append(',');
  1292. SeriesChartType seriesChartType = info.Series != null ?
  1293. info.Series.ChartType :
  1294. FormulaHelper.GetDefaultChartType(info.DataField);
  1295. IList<DataField> dataFields = FormulaHelper.GetDataFields(seriesChartType);
  1296. int dataFieldIndex = dataFields.IndexOf(info.DataField);
  1297. if (dataFieldIndex == 0)
  1298. sb.AppendFormat(CultureInfo.InvariantCulture, "{0}:Y", info.SeriesName); //The string field descriptor is 1 based ;-(
  1299. else
  1300. sb.AppendFormat(CultureInfo.InvariantCulture, "{0}:Y{1}", info.SeriesName, dataFieldIndex + 1); //The string field descriptor is 1 based ;-(
  1301. }
  1302. return sb.ToString();
  1303. }
  1304. //Static
  1305. /// <summary>
  1306. /// Parse the string defining the formula's input/output series and fields.
  1307. /// </summary>
  1308. /// <param name="chart">The chart.</param>
  1309. /// <param name="seriesFields">The series fields list. The series name can be followed by the field names. For example: "Series1:Y,Series1:Y3,Series2:Close"</param>
  1310. /// <param name="formulaFields">The formula fields list.</param>
  1311. /// <returns></returns>
  1312. public static SeriesFieldList FromString(Chart chart, string seriesFields, IList<DataField> formulaFields)
  1313. {
  1314. SeriesFieldList result = new SeriesFieldList();
  1315. if (String.IsNullOrEmpty(seriesFields))
  1316. {
  1317. return result;
  1318. }
  1319. List<DataField> unmappedFormulaFields = new List<DataField>(formulaFields);
  1320. //Loop through the series/field pairs
  1321. foreach (string seriesField in seriesFields.Split(','))
  1322. {
  1323. //Stop processing if all the formula fields are mapped
  1324. if (unmappedFormulaFields.Count == 0)
  1325. break;
  1326. //Split a pair into a series + field
  1327. string[] seriesFieldParts = seriesField.Split(':');
  1328. if (seriesFieldParts.Length > 2)
  1329. {
  1330. throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(seriesField));
  1331. }
  1332. //Get the series and series fields
  1333. string seriesName = seriesFieldParts[0].Trim();
  1334. Series series = chart.Series.FindByName(seriesName);
  1335. if (series != null)
  1336. {
  1337. switch (seriesFieldParts.Length)
  1338. {
  1339. case 1: //Only series name is specified: "Series1"
  1340. AddSeriesFieldInfo(result, series, unmappedFormulaFields);
  1341. break;
  1342. case 2: //Series and field names are provided: "Series1:Y3"
  1343. AddSeriesFieldInfo(result, series, unmappedFormulaFields, seriesFieldParts[1]);
  1344. break;
  1345. }
  1346. }
  1347. else
  1348. {
  1349. switch (seriesFieldParts.Length)
  1350. {
  1351. case 1: //Only series name is specified: "Series1"
  1352. AddSeriesFieldInfo(result, seriesName, unmappedFormulaFields);
  1353. break;
  1354. case 2: //Series and field names are provided: "Series1:Y3"
  1355. AddSeriesFieldInfo(result, seriesName, unmappedFormulaFields, seriesFieldParts[1]);
  1356. break;
  1357. }
  1358. }
  1359. }
  1360. return result;
  1361. }
  1362. /// <summary>
  1363. /// Adds the series field info.
  1364. /// </summary>
  1365. /// <param name="result">The result.</param>
  1366. /// <param name="series">The series.</param>
  1367. /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
  1368. private static void AddSeriesFieldInfo(SeriesFieldList result, Series series, IList<DataField> unmappedFormulaFields)
  1369. {
  1370. List<DataField> seriesFields = new List<DataField>(FormulaHelper.GetDataFields(series.ChartType));
  1371. for (int i = 0; i < unmappedFormulaFields.Count && seriesFields.Count > 0; )
  1372. {
  1373. DataField formulaField = unmappedFormulaFields[i];
  1374. DataField? seriesField = null;
  1375. // Case 1. Check if the formulaField is valid for this chart type
  1376. if (seriesFields.Contains(formulaField))
  1377. {
  1378. seriesField = formulaField;
  1379. }
  1380. // Case 2. Try to map the formula field to the series field
  1381. if (seriesField == null)
  1382. {
  1383. seriesField = FormulaHelper.MapFormulaDataField(series.ChartType, formulaField);
  1384. }
  1385. // If the seriesField is found - add it to the results
  1386. if (seriesField != null)
  1387. {
  1388. result.Add(new SeriesFieldInfo(series, (DataField)seriesField));
  1389. seriesFields.Remove((DataField)formulaField);
  1390. unmappedFormulaFields.Remove(formulaField);
  1391. }
  1392. else
  1393. {
  1394. i++;
  1395. }
  1396. }
  1397. }
  1398. /// <summary>
  1399. /// Adds the series field info.
  1400. /// </summary>
  1401. /// <param name="result">The result.</param>
  1402. /// <param name="series">The series.</param>
  1403. /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
  1404. /// <param name="seriesFieldId">The series field id.</param>
  1405. private static void AddSeriesFieldInfo(SeriesFieldList result, Series series, IList<DataField> unmappedFormulaFields, string seriesFieldId)
  1406. {
  1407. IList<DataField> seriesFields = FormulaHelper.GetDataFields(series.ChartType);
  1408. DataField? seriesField = null;
  1409. seriesFieldId = seriesFieldId.ToUpperInvariant().Trim();
  1410. if (seriesFieldId == "Y")
  1411. {
  1412. seriesField = seriesFields[0];
  1413. }
  1414. else if (seriesFieldId.StartsWith("Y", StringComparison.Ordinal))
  1415. {
  1416. int id = 0;
  1417. if (int.TryParse(seriesFieldId.Substring(1), out id))
  1418. if (id - 1 < seriesFields.Count)
  1419. {
  1420. seriesField = seriesFields[id - 1];
  1421. }
  1422. else
  1423. {
  1424. throw (new ArgumentException(SR.ExceptionFormulaYIndexInvalid, seriesFieldId));
  1425. }
  1426. }
  1427. else
  1428. {
  1429. seriesField = (DataField)Enum.Parse(typeof(DataField), seriesFieldId, true);
  1430. }
  1431. // Add the seriesField to the results
  1432. if (seriesField != null)
  1433. {
  1434. result.Add(new SeriesFieldInfo(series, (DataField)seriesField));
  1435. if (unmappedFormulaFields.Contains((DataField)seriesField))
  1436. unmappedFormulaFields.Remove((DataField)seriesField);
  1437. else
  1438. unmappedFormulaFields.RemoveAt(0);
  1439. }
  1440. else
  1441. {
  1442. throw new ArgumentException(SR.ExceptionDataPointValueNameInvalid, seriesFieldId);
  1443. }
  1444. }
  1445. /// <summary>
  1446. /// Adds the series field info.
  1447. /// </summary>
  1448. /// <param name="result">The result.</param>
  1449. /// <param name="seriesName">Name of the series.</param>
  1450. /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
  1451. private static void AddSeriesFieldInfo(SeriesFieldList result, string seriesName, IList<DataField> unmappedFormulaFields)
  1452. {
  1453. SeriesChartType chartType = FormulaHelper.GetDefaultChartType(unmappedFormulaFields[0]);
  1454. List<DataField> seriesFields = new List<DataField>(FormulaHelper.GetDataFields(chartType));
  1455. for (int i = 0; i < unmappedFormulaFields.Count && seriesFields.Count > 0; )
  1456. {
  1457. DataField formulaField = unmappedFormulaFields[i];
  1458. DataField? seriesField = null;
  1459. // Check if the formulaField is valid for this chart type
  1460. if (seriesFields.Contains(formulaField))
  1461. {
  1462. seriesField = formulaField;
  1463. }
  1464. // If the seriesField is found - add it to the results
  1465. if (seriesField != null)
  1466. {
  1467. result.Add(new SeriesFieldInfo(seriesName, (DataField)seriesField));
  1468. seriesFields.Remove((DataField)formulaField);
  1469. unmappedFormulaFields.Remove(formulaField);
  1470. }
  1471. else
  1472. {
  1473. i++;
  1474. }
  1475. }
  1476. }
  1477. /// <summary>
  1478. /// Adds the series field info.
  1479. /// </summary>
  1480. /// <param name="result">The result.</param>
  1481. /// <param name="seriesName">Name of the series.</param>
  1482. /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
  1483. /// <param name="seriesFieldId">The series field id.</param>
  1484. private static void AddSeriesFieldInfo(SeriesFieldList result, string seriesName, IList<DataField> unmappedFormulaFields, string seriesFieldId)
  1485. {
  1486. SeriesChartType chartType = FormulaHelper.GetDefaultChartType(unmappedFormulaFields[0]);
  1487. IList<DataField> seriesFields = FormulaHelper.GetDataFields(chartType);
  1488. //Find the field
  1489. DataField? seriesField = null;
  1490. seriesFieldId = seriesFieldId.ToUpperInvariant().Trim();
  1491. if (seriesFieldId == "Y")
  1492. {
  1493. seriesField = seriesFields[0];
  1494. }
  1495. else if (seriesFieldId.StartsWith("Y", StringComparison.Ordinal))
  1496. {
  1497. int seriesFieldIndex = 0;
  1498. if (int.TryParse(seriesFieldId.Substring(1), out seriesFieldIndex))
  1499. if (seriesFieldIndex < seriesFields.Count)
  1500. {
  1501. seriesField = seriesFields[seriesFieldIndex - 1];
  1502. }
  1503. else
  1504. {
  1505. throw (new ArgumentException(SR.ExceptionFormulaYIndexInvalid, seriesFieldId));
  1506. }
  1507. }
  1508. else
  1509. {
  1510. //Try parse the field name
  1511. try
  1512. {
  1513. seriesField = (DataField)Enum.Parse(typeof(DataField), seriesFieldId, true);
  1514. }
  1515. catch (ArgumentException)
  1516. { }
  1517. }
  1518. if (seriesField != null)
  1519. {
  1520. result.Add(new SeriesFieldInfo(seriesName, (DataField)seriesField));
  1521. unmappedFormulaFields.Remove((DataField)seriesField);
  1522. }
  1523. else
  1524. {
  1525. throw new ArgumentException(SR.ExceptionDataPointValueNameInvalid, seriesFieldId);
  1526. }
  1527. }
  1528. }
  1529. #endregion
  1530. }