Oscillator.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  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. //
  5. // Purpose: This class is used to calculate oscillator
  6. // indicators used in Technical Analyses.
  7. //
  8. using System;
  9. using System.Globalization;
  10. namespace FastReport.DataVisualization.Charting.Formulas
  11. {
  12. /// <summary>
  13. /// This class is used to calculate oscillator
  14. /// indicators used in Technical Analyses.
  15. /// </summary>
  16. internal class Oscillators : PriceIndicators
  17. {
  18. #region Properties
  19. /// <summary>
  20. /// Formula Module name
  21. /// </summary>
  22. override public string Name { get{ return "Oscillators";}}
  23. #endregion
  24. #region Formulas
  25. /// <summary>
  26. /// The Chaikin Oscillator is created by subtracting a 10 period
  27. /// exponential moving average of the Accumulation/Distribution
  28. /// line from a 3 period moving average of the
  29. /// Accumulation/Distribution Line.
  30. /// ---------------------------------------------------------
  31. /// Input:
  32. /// - 4 Y values ( Hi, Low, Close, Volume ).
  33. /// Output:
  34. /// - 1 Y value Chaikin Oscillator
  35. /// Parameters:
  36. /// - Short Period for Exponential Moving average (default=3)
  37. /// - Int64 Period for Exponential Moving average (default=10)
  38. /// Extra Parameters:
  39. /// - Start from First
  40. /// </summary>
  41. /// <param name="inputValues">Arrays of doubles - Input values</param>
  42. /// <param name="outputValues">Arrays of doubles - Output values</param>
  43. /// <param name="parameterList">Array of strings - Parameters</param>
  44. /// <param name="extraParameterList">Array of strings - Extra parameters</param>
  45. private void ChaikinOscillator(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
  46. {
  47. // There is no enough input series
  48. if( inputValues.Length != 5 )
  49. {
  50. throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresFourArrays);
  51. }
  52. // Different number of x and y values
  53. CheckNumOfValues( inputValues, 4 );
  54. // Short Period for Exp moving average
  55. int shortPeriod;
  56. if (parameterList.Length < 1 ||
  57. !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out shortPeriod))
  58. {
  59. shortPeriod = 3;
  60. }
  61. // Int64 Period for Exp moving average
  62. int longPeriod;
  63. if (parameterList.Length < 2 ||
  64. !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out longPeriod))
  65. {
  66. longPeriod = 10;
  67. }
  68. if( shortPeriod > longPeriod || longPeriod <= 0 || shortPeriod <= 0 )
  69. {
  70. throw new ArgumentException(SR.ExceptionOscillatorObjectInvalidPeriod);
  71. }
  72. // Starting average from the first data point or after period.
  73. bool startFromFirst = bool.Parse( extraParameterList[0] );
  74. VolumeIndicators volume = new VolumeIndicators();
  75. double [][] outputDistribution = new double [2][];
  76. // Accumulation Distribution
  77. volume.AccumulationDistribution( inputValues, out outputDistribution );
  78. double [] ExpAvgDistribution;
  79. // Exponential Moving average of Accumulation Distribution
  80. ExponentialMovingAverage(outputDistribution[1],out ExpAvgDistribution,longPeriod,startFromFirst);
  81. double [] ExpAvg;
  82. // Exponential Moving average of close
  83. ExponentialMovingAverage(outputDistribution[1],out ExpAvg,shortPeriod,startFromFirst);
  84. outputValues = new double [2][];
  85. int period = Math.Min(ExpAvg.Length,ExpAvgDistribution.Length);
  86. outputValues[0] = new double [period];
  87. outputValues[1] = new double [period];
  88. // Accumulation Distribution
  89. int expIndex = 0;
  90. for( int index = inputValues[1].Length - period; index < inputValues[1].Length; index++ )
  91. {
  92. // Set X values
  93. outputValues[0][expIndex] = inputValues[0][index];
  94. // Set Y values
  95. if(startFromFirst)
  96. {
  97. // Number of items in all arays is the same and they are aligned by time.
  98. outputValues[1][expIndex] = ExpAvg[expIndex] - ExpAvgDistribution[expIndex];
  99. }
  100. else if( (expIndex + longPeriod - shortPeriod) < ExpAvg.Length)
  101. {
  102. // Number of items in MovingAverages arrays is different and requires adjustment.
  103. outputValues[1][expIndex] = ExpAvg[expIndex + longPeriod - shortPeriod] - ExpAvgDistribution[expIndex];
  104. }
  105. else
  106. {
  107. outputValues[1][expIndex] = Double.NaN;
  108. }
  109. expIndex++;
  110. }
  111. }
  112. /// <summary>
  113. /// The Detrended Price Oscillator ("DPO") attempts to
  114. /// eliminate the trend in prices. Detrended prices allow
  115. /// you to more easily identify cycles and overbought/oversold
  116. /// levels. To calculate the DPO, you specify a time period.
  117. /// Cycles longer than this time period are removed from
  118. /// prices, leaving the shorter-term cycles.
  119. /// ---------------------------------------------------------
  120. /// Input:
  121. /// - 1 Y value ( Close ).
  122. /// Output:
  123. /// - 1 Y value Detrended Price Oscillator
  124. /// Parameters:
  125. /// - Period
  126. /// </summary>
  127. /// <param name="inputValues">Arrays of doubles - Input values</param>
  128. /// <param name="outputValues">Arrays of doubles - Output values</param>
  129. /// <param name="parameterList">Array of strings - Parameters</param>
  130. private void DetrendedPriceOscillator(double [][] inputValues, out double [][] outputValues, string [] parameterList)
  131. {
  132. // There is no enough input series
  133. if( inputValues.Length != 2 )
  134. {
  135. throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
  136. }
  137. // Different number of x and y values
  138. CheckNumOfValues( inputValues, 1 );
  139. // Short Period for Exp moving average
  140. int period;
  141. try
  142. {period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
  143. catch( Exception e )
  144. {
  145. if (e.Message == SR.ExceptionObjectReferenceIsNull)
  146. throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
  147. else
  148. throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
  149. }
  150. if( period <= 0 )
  151. throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
  152. double [] outputAverage;
  153. // Moving Average
  154. MovingAverage( inputValues[1], out outputAverage, period, false );
  155. outputValues = new double [2][];
  156. outputValues[0] = new double [inputValues[0].Length - period*3/2];
  157. outputValues[1] = new double [inputValues[1].Length - period*3/2];
  158. // Detrended Price Oscillator
  159. for( int index = 0; index < outputValues[1].Length; index++ )
  160. {
  161. // Set X values
  162. outputValues[0][index] = inputValues[0][index + period + period/2];
  163. // Set Y values
  164. outputValues[1][index] = inputValues[1][index + period + period/2] - outputAverage[index];
  165. }
  166. }
  167. /// <summary>
  168. /// Chaikin's Volatility indicator compares the spread
  169. /// between a security's high and low prices.
  170. /// It quantifies volatility as a widening of the range
  171. /// between the high and the low price. There are two ways
  172. /// to interpret this measure of volatility. One method
  173. /// assumes that market tops are generally accompanied by
  174. /// increased volatility (as investors get nervous and
  175. /// indecisive) and that the latter stages of a market
  176. /// bottom are generally accompanied by decreased volatility
  177. /// (as investors get bored). Another method (Mr. Chaikin's)
  178. /// assumes that an increase in the Volatility indicator over
  179. /// a relatively short time period indicates that a bottom is
  180. /// near (e.g., a panic sell-off) and that a decrease in
  181. /// volatility over a longer time period indicates an
  182. /// approaching top (e.g., a mature bull market). As with
  183. /// almost all experienced investors, Mr. Chaikin recommends
  184. /// that you do not rely on any one indicator. He suggests
  185. /// using a moving average penetration or trading band system
  186. /// to confirm this (or any) indicator.
  187. /// ---------------------------------------------------------
  188. /// Input:
  189. /// - 2 Y values ( Hi, Low ).
  190. /// Output:
  191. /// - 1 Y value Volatility Chaikins
  192. /// Parameters:
  193. /// - Periods (default 10)- is used to specify the Shift days, By default this property is set to 10.
  194. /// - SignalPeriod (default 10)- is used to calculate Exponential Moving Avg of the Signal line, By default this property is set to 10.
  195. /// </summary>
  196. /// <param name="inputValues">Arrays of doubles - Input values</param>
  197. /// <param name="outputValues">Arrays of doubles - Output values</param>
  198. /// <param name="parameterList">Array of strings - Parameters</param>
  199. private void VolatilityChaikins(double [][] inputValues, out double [][] outputValues, string [] parameterList)
  200. {
  201. // There is no enough input series
  202. if( inputValues.Length != 3 )
  203. {
  204. throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
  205. }
  206. // Different number of x and y values
  207. CheckNumOfValues( inputValues, 2 );
  208. // Period
  209. int period;
  210. if (parameterList.Length < 1 ||
  211. !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
  212. {
  213. period = 10;
  214. }
  215. if( period <= 0 )
  216. throw new InvalidOperationException(SR.ExceptionOscillatorNegativePeriodParameter);
  217. // Signal Period for Exp moving average
  218. int signalPeriod;
  219. if (parameterList.Length < 2 ||
  220. !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out signalPeriod))
  221. {
  222. signalPeriod = 10;
  223. }
  224. if( signalPeriod <= 0 )
  225. throw new InvalidOperationException(SR.ExceptionOscillatorNegativeSignalPeriod);
  226. double [] outputAverage;
  227. double [] hiLowInput = new double[inputValues[1].Length];
  228. // Find Hi - Low
  229. for( int index = 0; index < inputValues[1].Length; index++ )
  230. {
  231. hiLowInput[index] = inputValues[1][index] - inputValues[2][index];
  232. }
  233. // Exponential Moving Average
  234. ExponentialMovingAverage( hiLowInput, out outputAverage, signalPeriod, false );
  235. outputValues = new double [2][];
  236. outputValues[0] = new double [outputAverage.Length - period];
  237. outputValues[1] = new double [outputAverage.Length - period];
  238. // Volatility Chaikins
  239. for( int index = 0; index < outputValues[1].Length; index++ )
  240. {
  241. // Set X values
  242. outputValues[0][index] = inputValues[0][index + period + signalPeriod - 1];
  243. // Set Y values
  244. if( outputAverage[index] != 0.0 )
  245. outputValues[1][index] = ( outputAverage[index + period] - outputAverage[index] ) / outputAverage[index] * 100.0;
  246. else
  247. // Div with zero error.
  248. outputValues[1][index] = 0.0;
  249. }
  250. }
  251. /// <summary>
  252. /// The Volume Oscillator displays the difference between two
  253. /// moving averages of a security's volume. The difference
  254. /// between the moving averages can be expressed in either
  255. /// points or percentages. You can use the difference between
  256. /// two moving averages of volume to determine if the overall
  257. /// volume trend is increasing or decreasing. When the Volume
  258. /// Oscillator rises above zero, it signifies that the
  259. /// shorter-term volume moving average has risen above
  260. /// the longer-term volume moving average, and thus, that
  261. /// the short-term volume trend is higher (i.e., more volume)
  262. /// than the longer-term volume trend.
  263. /// ---------------------------------------------------------
  264. /// Input:
  265. /// - 1 Y values ( Volume ).
  266. /// Output:
  267. /// - 1 Y value VolumeOscillator
  268. /// Parameters:
  269. /// - ShortPeriod (Default 5)= is used to configure the short period.
  270. /// - LongPeriod (Default 10)= is used to configure the Int64 period.
  271. /// - Percentage (Default true)= The Volume Oscillator can display the difference between the two moving averages as either points or percentages.
  272. /// </summary>
  273. /// <param name="inputValues">Arrays of doubles - Input values</param>
  274. /// <param name="outputValues">Arrays of doubles - Output values</param>
  275. /// <param name="parameterList">Array of strings - Parameters</param>
  276. private void VolumeOscillator(double [][] inputValues, out double [][] outputValues, string [] parameterList)
  277. {
  278. // There is no enough input series
  279. if( inputValues.Length != 2 )
  280. {
  281. throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
  282. }
  283. // Different number of x and y values
  284. CheckNumOfValues( inputValues, 1 );
  285. // Short Period
  286. int shortPeriod;
  287. if (parameterList.Length < 1 ||
  288. !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out shortPeriod))
  289. {
  290. shortPeriod = 5;
  291. }
  292. // Int64 Period
  293. int longPeriod;
  294. if (parameterList.Length < 2 ||
  295. !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out longPeriod))
  296. {
  297. longPeriod = 10;
  298. }
  299. if( shortPeriod > longPeriod || longPeriod <= 0 || shortPeriod <= 0 )
  300. throw new ArgumentException(SR.ExceptionOscillatorObjectInvalidPeriod);
  301. // percentage
  302. bool percentage;
  303. if (parameterList.Length < 3 ||
  304. !bool.TryParse(parameterList[2], out percentage))
  305. {
  306. percentage = true;
  307. }
  308. double [] shortAverage;
  309. double [] longAverage;
  310. // Find Short moving average
  311. MovingAverage( inputValues[1], out shortAverage, shortPeriod, false );
  312. // Find Int64 moving average
  313. MovingAverage( inputValues[1], out longAverage, longPeriod, false );
  314. outputValues = new double [2][];
  315. outputValues[0] = new double [longAverage.Length];
  316. outputValues[1] = new double [longAverage.Length];
  317. // Volume Oscillator
  318. for( int index = 0; index < longAverage.Length; index++ )
  319. {
  320. // Set X values
  321. outputValues[0][index] = inputValues[0][index + longPeriod-1];
  322. // Set Y values
  323. outputValues[1][index] = shortAverage[index + shortPeriod] - longAverage[index];
  324. // RecalculateAxesScale difference in %
  325. if( percentage )
  326. {
  327. // Div by zero error.
  328. if( longAverage[index] == 0.0 )
  329. outputValues[1][index]=0.0;
  330. else
  331. outputValues[1][index] = outputValues[1][index] / shortAverage[index + shortPeriod] * 100;
  332. }
  333. }
  334. }
  335. /// <summary>
  336. /// The Stochastic Indicator is based on the observation that
  337. /// as prices increase, closing prices tend to accumulate ever
  338. /// closer to the highs for the period. Conversely, as prices
  339. /// decrease, closing prices tend to accumulate ever closer to
  340. /// the lows for the period. Trading decisions are made with
  341. /// respect to divergence between % of "D" (one of the two
  342. /// lines generated by the study) and the item's price. For
  343. /// example, when a commodity or stock makes a high, reacts,
  344. /// and subsequently moves to a higher high while corresponding
  345. /// peaks on the % of "D" line make a high and then a lower
  346. /// high, a bearish divergence is indicated. When a commodity
  347. /// or stock has established a new low, reacts, and moves to a
  348. /// lower low while the corresponding low points on the % of
  349. /// "D" line make a low and then a higher low, a bullish
  350. /// divergence is indicated. Traders act upon this divergence
  351. /// when the other line generated by the study (K) crosses on
  352. /// the right-hand side of the peak of the % of "D" line in the
  353. /// case of a top, or on the right-hand side of the low point
  354. /// of the % of "D" line in the case of a bottom. The Stochastic
  355. /// Oscillator is displayed as two lines. The main line is
  356. /// called "%K." The second line, called "%D," is a moving
  357. /// average of %K.
  358. /// ---------------------------------------------------------
  359. /// Input:
  360. /// - 3 Y values ( Hi, Low, Close ).
  361. /// Output:
  362. /// - 2 Y value ( %K, %D )
  363. /// Parameters:
  364. /// - PeriodD (Default 10) = is used for %D calculation as SMA of %K.
  365. /// - PeriodK (Default 10) = is used to calculate %K.
  366. /// </summary>
  367. /// <param name="inputValues">Arrays of doubles - Input values</param>
  368. /// <param name="outputValues">Arrays of doubles - Output values</param>
  369. /// <param name="parameterList">Array of strings - Parameters</param>
  370. internal void StochasticIndicator(double [][] inputValues, out double [][] outputValues, string [] parameterList)
  371. {
  372. // There is no enough input series
  373. if( inputValues.Length != 4 )
  374. {
  375. throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
  376. }
  377. // Different number of x and y values
  378. CheckNumOfValues( inputValues, 3 );
  379. // PeriodD for moving average
  380. int periodD;
  381. if (parameterList.Length < 2 ||
  382. !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out periodD))
  383. {
  384. periodD = 10;
  385. }
  386. if( periodD <= 0 )
  387. throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
  388. // PeriodK for moving average
  389. int periodK;
  390. if (parameterList.Length < 1 ||
  391. !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out periodK))
  392. {
  393. periodK = 10;
  394. }
  395. if( periodK <= 0 )
  396. throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
  397. // Output arrays
  398. outputValues = new double [3][];
  399. // X
  400. outputValues[0] = new double [inputValues[0].Length - periodK - periodD + 2];
  401. // K%
  402. outputValues[1] = new double [inputValues[0].Length - periodK - periodD + 2];
  403. // D%
  404. outputValues[2] = new double [inputValues[0].Length - periodK - periodD + 2];
  405. double [] K = new double [inputValues[0].Length - periodK + 1];
  406. // Find K%
  407. for( int index = periodK - 1; index < inputValues[0].Length; index++ )
  408. {
  409. // Find Lowest Low and Highest High
  410. double minLow = double.MaxValue;
  411. double maxHi = double.MinValue;
  412. for( int indexHL = index - periodK + 1; indexHL <= index; indexHL++ )
  413. {
  414. if( minLow > inputValues[2][indexHL] )
  415. minLow = inputValues[2][indexHL];
  416. if( maxHi < inputValues[1][indexHL] )
  417. maxHi = inputValues[1][indexHL];
  418. }
  419. // Find K%
  420. K[index - periodK + 1] = ( inputValues[3][index] - minLow ) / ( maxHi - minLow ) * 100;
  421. // Set X and Y K output
  422. if( index >= periodK + periodD - 2 )
  423. {
  424. outputValues[0][index - periodK - periodD + 2] = inputValues[0][index];
  425. outputValues[1][index - periodK - periodD + 2] = K[index - periodK + 1];
  426. }
  427. }
  428. // Find D%
  429. MovingAverage( K, out outputValues[2], periodD, false );
  430. }
  431. /// <summary>
  432. /// Williams’ %R (pronounced "percent R") is a momentum
  433. /// indicator that measures overbought/oversold levels.
  434. /// Williams’ %R was developed by Larry Williams. The
  435. /// interpretation of Williams' %R is very similar to that
  436. /// of the Stochastic Oscillator except that %R is plotted
  437. /// upside-down and the Stochastic Oscillator has internal
  438. /// smoothing. To display the Williams’ %R indicator on an
  439. /// upside-down scale, it is usually plotted using negative
  440. /// values (e.g., -20%). Readings in the range of 80 to 100%
  441. /// indicate that the security is oversold while readings in
  442. /// the 0 to 20% range suggest that it is overbought.
  443. /// As with all overbought/oversold indicators, it is best to
  444. /// wait for the security's price to change direction before
  445. /// placing your trades. For example, if an overbought/oversold
  446. /// indicator (such as the Stochastic Oscillator or Williams'
  447. /// %R) is showing an overbought condition, it is wise to wait
  448. /// for the security's price to turn down before selling the
  449. /// security. (The MovingAverageConvergenceDivergence is a good indicator to monitor change
  450. /// in a security's price.) It is not unusual for
  451. /// overbought/oversold indicators to remain in an
  452. /// overbought/oversold condition for a long time period as
  453. /// the security's price continues to climb/fall. Selling
  454. /// simply because the security appears overbought may take
  455. /// you out of the security long before its price shows signs
  456. /// of deterioration.
  457. /// ---------------------------------------------------------
  458. /// Input:
  459. /// - 3 Y values ( Hi, Low, Close ).
  460. /// Output:
  461. /// - 2 Y value ( %R )
  462. /// Parameters:
  463. /// - Period (Default 14) = is used to configure the number of periods to calculate the WilliamsR
  464. /// </summary>
  465. /// <param name="inputValues">Arrays of doubles - Input values</param>
  466. /// <param name="outputValues">Arrays of doubles - Output values</param>
  467. /// <param name="parameterList">Array of strings - Parameters</param>
  468. internal void WilliamsR(double [][] inputValues, out double [][] outputValues, string [] parameterList)
  469. {
  470. // There is no enough input series
  471. if( inputValues.Length != 4 )
  472. throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
  473. // Different number of x and y values
  474. CheckNumOfValues( inputValues, 3 );
  475. // PeriodD for moving average
  476. int period;
  477. if (parameterList.Length < 1 ||
  478. !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
  479. {
  480. period = 14;
  481. }
  482. if( period <= 0 )
  483. throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
  484. // Output arrays
  485. outputValues = new double [2][];
  486. // X
  487. outputValues[0] = new double [inputValues[0].Length - period + 1];
  488. // R%
  489. outputValues[1] = new double [inputValues[0].Length - period + 1];
  490. // Find R%
  491. for( int index = period - 1; index < inputValues[0].Length; index++ )
  492. {
  493. // Find Lowest Low and Highest High
  494. double minLow = double.MaxValue;
  495. double maxHi = double.MinValue;
  496. for( int indexHL = index - period + 1; indexHL <= index; indexHL++ )
  497. {
  498. if( minLow > inputValues[2][indexHL] )
  499. minLow = inputValues[2][indexHL];
  500. if( maxHi < inputValues[1][indexHL] )
  501. maxHi = inputValues[1][indexHL];
  502. }
  503. // Set X value
  504. outputValues[0][index - period + 1] = inputValues[0][index];
  505. // Find R%
  506. outputValues[1][index - period + 1] = ( maxHi - inputValues[3][index] ) / ( maxHi - minLow ) * (-100.0);
  507. }
  508. }
  509. #endregion
  510. #region Methods
  511. /// <summary>
  512. /// Constructor
  513. /// </summary>
  514. public Oscillators()
  515. {
  516. }
  517. /// <summary>
  518. /// The first method in the module, which converts a formula
  519. /// name to the corresponding private method.
  520. /// </summary>
  521. /// <param name="formulaName">String which represent a formula name</param>
  522. /// <param name="inputValues">Arrays of doubles - Input values</param>
  523. /// <param name="outputValues">Arrays of doubles - Output values</param>
  524. /// <param name="parameterList">Array of strings - Formula parameters</param>
  525. /// <param name="extraParameterList">Array of strings - Extra Formula parameters from DataManipulator object</param>
  526. /// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
  527. override public void Formula( string formulaName, double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList, out string [][] outLabels )
  528. {
  529. string name;
  530. outputValues = null;
  531. // Not used for these formulas.
  532. outLabels = null;
  533. name = formulaName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
  534. try
  535. {
  536. switch( name )
  537. {
  538. case "STOCHASTICINDICATOR":
  539. StochasticIndicator( inputValues, out outputValues, parameterList );
  540. break;
  541. case "CHAIKINOSCILLATOR":
  542. ChaikinOscillator( inputValues, out outputValues, parameterList, extraParameterList );
  543. break;
  544. case "DETRENDEDPRICEOSCILLATOR":
  545. DetrendedPriceOscillator( inputValues, out outputValues, parameterList );
  546. break;
  547. case "VOLATILITYCHAIKINS":
  548. VolatilityChaikins( inputValues, out outputValues, parameterList );
  549. break;
  550. case "VOLUMEOSCILLATOR":
  551. VolumeOscillator( inputValues, out outputValues, parameterList );
  552. break;
  553. case "WILLIAMSR":
  554. WilliamsR( inputValues, out outputValues, parameterList );
  555. break;
  556. default:
  557. outputValues = null;
  558. break;
  559. }
  560. }
  561. catch( IndexOutOfRangeException )
  562. {
  563. throw new InvalidOperationException( SR.ExceptionFormulaInvalidPeriod( name ) );
  564. }
  565. catch( OverflowException )
  566. {
  567. throw new InvalidOperationException( SR.ExceptionFormulaNotEnoughDataPoints( name ) );
  568. }
  569. }
  570. #endregion
  571. }
  572. }