Skip to content

Commit

Permalink
rebased
Browse files Browse the repository at this point in the history
  • Loading branch information
David Pang committed Dec 1, 2023
1 parent f4a1a5b commit 1309d40
Show file tree
Hide file tree
Showing 4 changed files with 398 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

import org.ta4j.core.Bar;
import org.ta4j.core.BarSeries;
import org.ta4j.core.num.NaN;
import static org.ta4j.core.num.NaN.NaN;
import org.ta4j.core.num.Num;

Expand All @@ -34,69 +33,125 @@
*/
public class RecentSwingHighIndicator extends CachedIndicator<Num> {

/**
* A swing high is a bar (or sequence of bars) with a higher high than the bars
* both before and after it. Defines the number of bars to consider on each side
* (e.g., 2 bars on each side).
*/
private final int surroundingBars;
private final int surroundingLowerBars;
private final int allowedEqualBars;

/**
* * Full constructor
* Constructs a RecentSwingHighIndicator
*
* @param series
* @param surroundingBars
* @param series The BarSeries to be analyzed.
* @param surroundingLowerBars For a bar to be identified as a swing high, it
* must have a higher high than this number of bars
* both immediately preceding and immediately
* following
* @param allowedEqualBars For a looser definition of peak, instead of
* requiring the surrounding bars to be strictly
* lower highs we allow this number of equal highs
* to either side (i.e. flat-ish peak or plateau)
* @throws IllegalArgumentException if surroundingLowerBars is less than or
* equal to 0.
* @throws IllegalArgumentException if allowedEqualBars is less than 0.
*/
public RecentSwingHighIndicator(BarSeries series, int surroundingBars) {
public RecentSwingHighIndicator(BarSeries series, int surroundingLowerBars, int allowedEqualBars) {
super(series);

if (surroundingBars <= 0) {
throw new IllegalArgumentException("surroundingBars must be greater than 0");
if (surroundingLowerBars <= 0) {
throw new IllegalArgumentException("surroundingLowerBars must be greater than 0");
}
if (allowedEqualBars < 0) {
throw new IllegalArgumentException("allowedEqualBars must be 0 or greater");
}
this.surroundingBars = surroundingBars;
this.surroundingLowerBars = surroundingLowerBars;
this.allowedEqualBars = allowedEqualBars;
}

/**
* * Convenience constructor defaulting surroundingBars to 2
* * Constructs a RecentSwingHighIndicator with the specified BarSeries and
* surrounding lower bars count and a default allowed equal bars count of 0
*
* @param series
* @param surroundingLowerBars
*/
public RecentSwingHighIndicator(BarSeries series, int surroundingLowerBars) {
this(series, surroundingLowerBars, 0);
}

/**
* Constructs a RecentSwingHighIndicator with the specified BarSeries, a default
* surrounding lower bars count of 2, and a default allowed equal bars count of
* 0
*
* @param series The BarSeries to be analyzed.
*/
public RecentSwingHighIndicator(BarSeries series) {
this(series, 2);
this(series, 2, 0);
}

/**
* Calculates the value of the most recent swing high
* Validates if the specified bar at currentIndex, considering the direction,
* meets the criteria for being a swing high.
*
* @param index the bar index
* @return the value of the most recent swing high, otherwise {@link NaN}
* @param currentIndex The index of the current bar.
* @param direction The direction for comparison (-1 for previous bars, 1 for
* following bars).
* @return true if the bar at currentIndex is a swing high considering the
* specified direction; false otherwise.
*/
@Override
protected Num calculate(int index) {
if (index < surroundingBars) {
return NaN;
}
private boolean validateBars(int currentIndex, int direction) {
Num currentHighPrice = getBarSeries().getBar(currentIndex).getHighPrice();
int lowerBarsCount = 0;
int equalBarsCount = 0;

int endIndex = getBarSeries().getEndIndex();
for (int i = currentIndex + direction; i >= getBarSeries().getBeginIndex()
&& i <= getBarSeries().getEndIndex(); i += direction) {
Num comparisonHighPrice = getBarSeries().getBar(i).getHighPrice();

for (int i = Math.min(index - 1, endIndex); i >= surroundingBars; i--) {
boolean isSwingHigh = true;
Bar currentBar = getBarSeries().getBar(i);
if (currentHighPrice.isEqual(comparisonHighPrice)) {
equalBarsCount++;

for (int j = 1; j <= surroundingBars; j++) {
if (i + j > endIndex || i - j < 0
|| currentBar.getHighPrice().isLessThan(getBarSeries().getBar(i - j).getHighPrice())
|| currentBar.getHighPrice().isLessThan(getBarSeries().getBar(i + j).getHighPrice())) {
isSwingHigh = false;
break;
if (equalBarsCount > allowedEqualBars) {
return false;
}
} else if (currentHighPrice.isGreaterThan(comparisonHighPrice)) {
lowerBarsCount++;
if (lowerBarsCount == surroundingLowerBars) {
return true;
}
} else {
break;
}
}
return false;
}

/**
* Calculates the most recent swing high value up to the specified index.
*
* @param index The bar index up to which the calculation is done.
* @return The value of the most recent swing high if it exists; NaN otherwise.
*/
@Override
protected Num calculate(int index) {
if (index < surroundingLowerBars) {
return NaN;
}

if (isSwingHigh) {
return currentBar.getHighPrice();
for (int i = index; i >= getBarSeries().getBeginIndex(); i--) {
if (validateBars(i, -1) && validateBars(i, 1)) {
return getBarSeries().getBar(i).getHighPrice();
}
}

return NaN;
}

/**
* Returns the number of unstable bars as defined by the surroundingBars
* parameter.
*
* @return The number of unstable bars.
*/
public int getUnstableBars() {
return surroundingLowerBars;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@
*/
package org.ta4j.core.indicators;

import org.ta4j.core.Bar;
import org.ta4j.core.BarSeries;
import org.ta4j.core.num.NaN;
import static org.ta4j.core.num.NaN.NaN;
import org.ta4j.core.num.Num;

Expand All @@ -34,69 +32,125 @@
*/
public class RecentSwingLowIndicator extends CachedIndicator<Num> {

/**
* A swing low is a bar (or sequence of bars) with a lower low than the bars
* both before and after it. Defines the number of bars to consider on each side
* (e.g., 2 bars on each side).
*/
private final int surroundingBars;
private final int surroundingHigherBars;
private final int allowedEqualBars;

/**
* Full constructor
* Constructs a RecentSwingLowIndicator
*
* @param series
* @param surroundingBars
* @param series The BarSeries to be analyzed.
* @param surroundingHigherBars For a bar to be identified as a swing low, it
* must have a lower low than this number of bars
* both immediately preceding and immediately
* following
* @param allowedEqualBars For a looser definition of swing low, instead of
* requiring the surrounding bars to be strictly
* higher lows we allow this number of equal lows
* to either side (i.e. flat-ish valley)
* @throws IllegalArgumentException if surroundingLowerBars is less than or
* equal to 0.
* @throws IllegalArgumentException if allowedEqualBars is less than 0.
*/
public RecentSwingLowIndicator(BarSeries series, int surroundingBars) {
public RecentSwingLowIndicator(BarSeries series, int surroundingHigherBars, int allowedEqualBars) {
super(series);

if (surroundingBars <= 0) {
throw new IllegalArgumentException("surroundingBars must be greater than 0");
if (surroundingHigherBars <= 0) {
throw new IllegalArgumentException("surroundingHigherBars must be greater than 0");
}
this.surroundingBars = surroundingBars;
if (allowedEqualBars < 0) {
throw new IllegalArgumentException("allowedEqualBars must be 0 or greater");
}
this.surroundingHigherBars = surroundingHigherBars;
this.allowedEqualBars = allowedEqualBars;
}

/**
* Constructs a RecentSwingLowIndicator with the specified BarSeries and
* surrounding higher bars count and a default allowed equal bars of 0
*
* @param series The BarSeries to be analyzed.
* @param surroundingHigherBars The number of bars to consider on each side that
* must have higher lows to identify a swing low.
*/
public RecentSwingLowIndicator(BarSeries series, int surroundingHigherBars) {
this(series, surroundingHigherBars, 0);
}

/**
* Convenience constructor defaulting surroundingBars to 2
* Constructs a RecentSwingLowIndicator with the specified BarSeries, a default
* surrounding higher bars count of 2, and a default allowed equal bars of 0
*
* @param series
* @param series The BarSeries to be analyzed.
*/
public RecentSwingLowIndicator(BarSeries series) {
this(series, 2);
this(series, 2, 0);
}

/**
* Calculates the value of the most recent swing low
* Validates if the specified bar at currentIndex, considering the direction,
* meets the criteria for being a swing high.
*
* @param index the bar index
* @return the value of the most recent swing low, otherwise {@link NaN}
* @param currentIndex The index of the current bar.
* @param direction The direction for comparison (-1 for previous bars, 1 for
* following bars).
* @return true if the bar at currentIndex is a swing low considering the
* specified direction; false otherwise.
*/
@Override
protected Num calculate(int index) {
if (index < surroundingBars) {
return NaN;
}
private boolean validateBars(int currentIndex, int direction) {
Num currentLowPrice = getBarSeries().getBar(currentIndex).getLowPrice();
int higherBarsCount = 0;
int equalBarsCount = 0;

int endIndex = getBarSeries().getEndIndex();
for (int i = currentIndex + direction; i >= getBarSeries().getBeginIndex()
&& i <= getBarSeries().getEndIndex(); i += direction) {
Num comparisonLowPrice = getBarSeries().getBar(i).getLowPrice();

for (int i = Math.min(index - 1, endIndex); i >= surroundingBars; i--) {
boolean isSwingLow = true;
Bar currentBar = getBarSeries().getBar(i);
if (currentLowPrice.isEqual(comparisonLowPrice)) {
equalBarsCount++;

for (int j = 1; j <= surroundingBars; j++) {
if (i + j > endIndex || i - j < 0
|| currentBar.getLowPrice().isGreaterThan(getBarSeries().getBar(i - j).getLowPrice())
|| currentBar.getLowPrice().isGreaterThan(getBarSeries().getBar(i + j).getLowPrice())) {
isSwingLow = false;
break;
if (equalBarsCount > allowedEqualBars) {
return false;
}
} else if (currentLowPrice.isLessThan(comparisonLowPrice)) {
higherBarsCount++;
if (higherBarsCount == surroundingHigherBars) {
return true;
}
} else {
break;
}
}
return false;
}

/**
* Calculates the most recent swing low value up to the specified index.
*
* @param index The bar index up to which the calculation is done.
* @return The value of the most recent swing low if it exists; NaN otherwise.
*/
@Override
protected Num calculate(int index) {
if (index < surroundingHigherBars) {
return NaN;
}

if (isSwingLow) {
return currentBar.getLowPrice();
for (int i = index; i >= getBarSeries().getBeginIndex(); i--) {
if (validateBars(i, -1) && validateBars(i, 1)) {
return getBarSeries().getBar(i).getLowPrice();
}
}

return NaN;
}

/**
* Returns the number of unstable bars as defined by the surroundingHigherBars
* parameter.
*
* @return The number of unstable bars.
*/
public int getUnstableBars() {
return surroundingHigherBars;
}
}
Loading

0 comments on commit 1309d40

Please sign in to comment.