在stackoverflow上找到了一个实现,但也不确定在哪里找到它使用的包'com.perseus.analysis.calculator.technical.trend',如果你知道一个好的算法请告诉我,最终喜欢转换,并在c#中实现这里代码并链接到我获取代码的位置。
link:the post
界面......
public interface ISupportResistanceCalculator {
/**
* Identifies support / resistance levels.
*
* @param timeseries
* timeseries
* @param beginIndex
* starting point (inclusive)
* @param endIndex
* ending point (exclusive)
* @param segmentSize
* number of elements per internal segment
* @param rangePct
* range % (Example: 1.5%)
* @return A tuple with the list of support levels and a list of resistance
* levels
*/
Tuple<List<Level>, List<Level>> identify(List<Float> timeseries,
int beginIndex, int endIndex, int segmentSize, float rangePct);
}
还有班级......
/**
*
*/
package com.perseus.analysis.calculator.technical.trend;
import static com.perseus.analysis.constant.LevelType.RESISTANCE;
import static com.perseus.analysis.constant.LevelType.SUPPORT;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import com.google.common.collect.Lists;
import com.perseus.analysis.calculator.mean.IMeanCalculator;
import com.perseus.analysis.calculator.timeseries.ITimeSeriesCalculator;
import com.perseus.analysis.constant.LevelType;
import com.perseus.analysis.model.Tuple;
import com.perseus.analysis.model.technical.Level;
import com.perseus.analysis.model.timeseries.ITimeseries;
import com.perseus.analysis.util.CollectionUtils;
/**
* A support and resistance calculator.
*
* @author PRITESH
*
*/
public class SupportResistanceCalculator implements
ISupportResistanceCalculator {
static interface LevelHelper {
Float aggregate(List<Float> data);
LevelType type(float level, float priceAsOfDate, final float rangePct);
boolean withinRange(Float node, float rangePct, Float val);
}
static class Support implements LevelHelper {
@Override
public Float aggregate(final List<Float> data) {
return Collections.min(data);
}
@Override
public LevelType type(final float level, final float priceAsOfDate,
final float rangePct) {
final float threshold = level * (1 - (rangePct / 100));
return (priceAsOfDate < threshold) ? RESISTANCE : SUPPORT;
}
@Override
public boolean withinRange(final Float node, final float rangePct,
final Float val) {
final float threshold = node * (1 + (rangePct / 100f));
if (val < threshold)
return true;
return false;
}
}
static class Resistance implements LevelHelper {
@Override
public Float aggregate(final List<Float> data) {
return Collections.max(data);
}
@Override
public LevelType type(final float level, final float priceAsOfDate,
final float rangePct) {
final float threshold = level * (1 + (rangePct / 100));
return (priceAsOfDate > threshold) ? SUPPORT : RESISTANCE;
}
@Override
public boolean withinRange(final Float node, final float rangePct,
final Float val) {
final float threshold = node * (1 - (rangePct / 100f));
if (val > threshold)
return true;
return false;
}
}
private static final int SMOOTHEN_COUNT = 2;
private static final LevelHelper SUPPORT_HELPER = new Support();
private static final LevelHelper RESISTANCE_HELPER = new Resistance();
private final ITimeSeriesCalculator tsCalc;
private final IMeanCalculator meanCalc;
public SupportResistanceCalculator(final ITimeSeriesCalculator tsCalc,
final IMeanCalculator meanCalc) {
super();
this.tsCalc = tsCalc;
this.meanCalc = meanCalc;
}
@Override
public Tuple<List<Level>, List<Level>> identify(
final List<Float> timeseries, final int beginIndex,
final int endIndex, final int segmentSize, final float rangePct) {
final List<Float> series = this.seriesToWorkWith(timeseries,
beginIndex, endIndex);
// Split the timeseries into chunks
final List<List<Float>> segments = this.splitList(series, segmentSize);
final Float priceAsOfDate = series.get(series.size() - 1);
final List<Level> levels = Lists.newArrayList();
this.identifyLevel(levels, segments, rangePct, priceAsOfDate,
SUPPORT_HELPER);
this.identifyLevel(levels, segments, rangePct, priceAsOfDate,
RESISTANCE_HELPER);
final List<Level> support = Lists.newArrayList();
final List<Level> resistance = Lists.newArrayList();
this.separateLevels(support, resistance, levels);
// Smoothen the levels
this.smoothen(support, resistance, rangePct);
return new Tuple<>(support, resistance);
}
private void identifyLevel(final List<Level> levels,
final List<List<Float>> segments, final float rangePct,
final float priceAsOfDate, final LevelHelper helper) {
final List<Float> aggregateVals = Lists.newArrayList();
// Find min/max of each segment
for (final List<Float> segment : segments) {
aggregateVals.add(helper.aggregate(segment));
}
while (!aggregateVals.isEmpty()) {
final List<Float> withinRange = new ArrayList<>();
final Set<Integer> withinRangeIdx = new TreeSet<>();
// Support/resistance level node
final Float node = helper.aggregate(aggregateVals);
// Find elements within range
for (int i = 0; i < aggregateVals.size(); ++i) {
final Float f = aggregateVals.get(i);
if (helper.withinRange(node, rangePct, f)) {
withinRangeIdx.add(i);
withinRange.add(f);
}
}
// Remove elements within range
CollectionUtils.remove(aggregateVals, withinRangeIdx);
// Take an average
final float level = this.meanCalc.mean(
withinRange.toArray(new Float[] {}), 0, withinRange.size());
final float strength = withinRange.size();
levels.add(new Level(helper.type(level, priceAsOfDate, rangePct),
level, strength));
}
}
private List<List<Float>> splitList(final List<Float> series,
final int segmentSize) {
final List<List<Float>> splitList = CollectionUtils
.convertToNewLists(CollectionUtils.splitList(series,
segmentSize));
if (splitList.size() > 1) {
// If last segment it too small
final int lastIdx = splitList.size() - 1;
final List<Float> last = splitList.get(lastIdx);
if (last.size() <= (segmentSize / 1.5f)) {
// Remove last segment
splitList.remove(lastIdx);
// Move all elements from removed last segment to new last
// segment
splitList.get(lastIdx - 1).addAll(last);
}
}
return splitList;
}
private void separateLevels(final List<Level> support,
final List<Level> resistance, final List<Level> levels) {
for (final Level level : levels) {
if (level.getType() == SUPPORT) {
support.add(level);
} else {
resistance.add(level);
}
}
}
private void smoothen(final List<Level> support,
final List<Level> resistance, final float rangePct) {
for (int i = 0; i < SMOOTHEN_COUNT; ++i) {
this.smoothen(support, rangePct);
this.smoothen(resistance, rangePct);
}
}
/**
* Removes one of the adjacent levels which are close to each other.
*/
private void smoothen(final List<Level> levels, final float rangePct) {
if (levels.size() < 2)
return;
final List<Integer> removeIdx = Lists.newArrayList();
Collections.sort(levels);
for (int i = 0; i < (levels.size() - 1); i++) {
final Level currentLevel = levels.get(i);
final Level nextLevel = levels.get(i + 1);
final Float current = currentLevel.getLevel();
final Float next = nextLevel.getLevel();
final float difference = Math.abs(next - current);
final float threshold = (current * rangePct) / 100;
if (difference < threshold) {
final int remove = currentLevel.getStrength() >= nextLevel
.getStrength() ? i : i + 1;
removeIdx.add(remove);
i++; // start with next pair
}
}
CollectionUtils.remove(levels, removeIdx);
}
private List<Float> seriesToWorkWith(final List<Float> timeseries,
final int beginIndex, final int endIndex) {
if ((beginIndex == 0) && (endIndex == timeseries.size()))
return timeseries;
return timeseries.subList(beginIndex, endIndex);
}
}
答案 0 :(得分:0)
以上是上述代码的C#版本。我还没有测试过,但这几乎就是它。
public interface ISupportResistanceCalculator
{
/// <summary>
///
/// </summary>
/// <param name="timeseries">timeseries</param>
/// <param name="beginIndex">starting point (inclusive)</param>
/// <param name="endIndex">ending point (exclusive)</param>
/// <param name="segmentSize">number of elements per internal segment</param>
/// <param name="rangePct"> range % (Example: 1.5%)</param>
/// <returns> A tuple with the list of support levels and a list of resistance levels</returns>
Tuple<List<Level>, List<Level>> GetSupportResistance(List<float> timeseries,
int beginIndex, int endIndex, int segmentSize, float rangePct);
}
public enum LevelType
{
Support, Resistance
}
public class Tuple<TA, TB>
{
private readonly TA a;
private readonly TB b;
public Tuple(TA a, TB b)
{
this.a = a;
this.b = b;
}
public TA GetA()
{
return this.a;
}
public TB GetB()
{
return this.b;
}
public String ToString()
{
return "Tuple [a=" + this.a + ", b=" + this.b + "]";
}
}
public abstract class CollectionUtils
{
public static void Remove<T>(List<T> list,
List<int> indexes)
{
int i = 0;
for (int j = 0; j < indexes.Count; j++)
{
list.RemoveAt(j - i++);
}
}
public static IEnumerable<List<T>> IntoBatches<T>(IEnumerable<T> list, int size)
{
if (size < 1)
throw new ArgumentException();
var rest = list;
while (rest.Any())
{
yield return rest.Take(size).ToList();
rest = rest.Skip(size);
}
}
}
public class Level
{
private long serialVersionUID = -7561265699198045328L;
private LevelType type;
private readonly float level;
private readonly float strength;
public Level(LevelType type, float level, float strength)
{
this.type = type;
this.level = level;
this.strength = strength;
}
public new LevelType GetType()
{
return this.type;
}
public float GetLevel()
{
return this.level;
}
public float GetStrength()
{
return this.strength;
}
public String ToString()
{
return "Level [type=" + this.type + ", level=" + this.level
+ ", strength=" + this.strength + "]";
}
}
public interface ILevelHelper
{
float Aggregate(List<float> data);
LevelType Type(float level, float priceAsOfDate, float rangePct);
bool WithinRange(float node, float rangePct, float val);
}
public class Support : ILevelHelper
{
public float Aggregate(List<float> data)
{
return data.Min();
}
public LevelType Type(float level, float priceAsOfDate,
float rangePct)
{
float threshold = level * (1 - (rangePct / 100));
return (priceAsOfDate < threshold) ? LevelType.Resistance : LevelType.Support;
}
public bool WithinRange(float node, float rangePct,
float val)
{
float threshold = node * (1 + (rangePct / 100f));
if (val < threshold)
return true;
return false;
}
}
public class Resistance : ILevelHelper
{
public float Aggregate(List<float> data)
{
return data.Max();
}
public LevelType Type(float level, float priceAsOfDate,
float rangePct)
{
float threshold = level * (1 + (rangePct / 100));
return (priceAsOfDate > threshold) ? LevelType.Resistance : LevelType.Support;
}
public bool WithinRange(float node, float rangePct,
float val)
{
float threshold = node * (1 - (rangePct / 100f));
if (val > threshold)
return true;
return false;
}
}
public class SupportResistanceCalculator : ISupportResistanceCalculator
{
private static readonly int SMOOTHEN_COUNT = 2;
private static readonly ILevelHelper SupportHelper = new Support();
private static readonly ILevelHelper ResistanceHelper = new Resistance();
public Tuple<List<Level>, List<Level>> GetSupportResistance(
List<float> timeseries, int beginIndex,
int endIndex, int segmentSize, float rangePct)
{
List<float> series = this.SeriesToWorkWith(timeseries,
beginIndex, endIndex);
// Split the timeseries into chunks
List<List<float>> segments = this.SplitList(series, segmentSize);
float priceAsOfDate = series[series.Count - 1];
List<Level> levels = new List<Level>();
this.IdentifySRLevel(levels, segments, rangePct, priceAsOfDate,
SupportHelper);
this.IdentifySRLevel(levels, segments, rangePct, priceAsOfDate,
ResistanceHelper);
List<Level> support = new List<Level>();
List<Level> resistance = new List<Level>();
this.SeparateLevels(support, resistance, levels);
// Smoothen the levels
this.Smoothen(support, resistance, rangePct);
return new BullsEyeStockEx.Controllers.Tuple<List<Level>, List<Level>>(support, resistance);
}
private void IdentifySRLevel(List<Level> levels,
List<List<float>> segments, float rangePct,
float priceAsOfDate, ILevelHelper helper)
{
List<float> aggregateVals = new List<float>();
// Find min/max of each segment
foreach (var segment in segments)
{
aggregateVals.Add(helper.Aggregate(segment));
}
while (aggregateVals.Any())
{
List<float> withinRange = new List<float>();
HashSet<int> withinRangeIdx = new HashSet<int>();
// Support/resistance level node
float node = helper.Aggregate(aggregateVals);
// Find elements within range
for (int i = 0; i < aggregateVals.Count; ++i)
{
float f = aggregateVals[i];
if (helper.WithinRange(node, rangePct, f))
{
withinRangeIdx.Add(i);
withinRange.Add(f);
}
}
// Remove elements within range
CollectionUtils.Remove(aggregateVals, withinRangeIdx.ToList());
// Take an average
float level = withinRange.Average();
float strength = withinRange.Count;
levels.Add(new Level(helper.Type(level, priceAsOfDate, rangePct),
level, strength));
}
}
private List<List<float>> SplitList(List<float> series,
int segmentSize)
{
List<List<float>> splitList = CollectionUtils.IntoBatches(series, segmentSize).ToList();
if (splitList.Count > 1)
{
// If last segment it too small
int lastIdx = splitList.Count - 1;
List<float> last = splitList[lastIdx].ToList();
if (last.Count <= (segmentSize / 1.5f))
{
// Remove last segment
splitList.Remove(last);
// Move all elements from removed last segment to new last
// segment
foreach (var l in last)
{
splitList[lastIdx - 1].Add(l);
}
}
}
return splitList.ToList();
}
private void SeparateLevels(List<Level> support,
List<Level> resistance, List<Level> levels)
{
foreach (var level in levels)
{
if (level.GetType() == LevelType.Support)
{
support.Add(level);
}
else
{
resistance.Add(level);
}
}
}
private void Smoothen(List<Level> support,
List<Level> resistance, float rangePct)
{
for (int i = 0; i < SMOOTHEN_COUNT; ++i)
{
this.Smoothen(support, rangePct);
this.Smoothen(resistance, rangePct);
}
}
/**
* Removes one of the adjacent levels which are close to each other.
*/
private void Smoothen(List<Level> levels, float rangePct)
{
if (levels.Count < 2)
return;
List<int> removeIdx = new List<int>();
levels.Sort();
for (int i = 0; i < (levels.Count - 1); i++)
{
Level currentLevel = levels[i];
Level nextLevel = levels[i + 1];
float current = currentLevel.GetLevel();
float next = nextLevel.GetLevel();
float difference = Math.Abs(next - current);
float threshold = (current * rangePct) / 100;
if (difference < threshold)
{
int remove = currentLevel.GetStrength() >= nextLevel
.GetStrength()
? i
: i + 1;
removeIdx.Add(remove);
i++; // start with next pair
}
}
CollectionUtils.Remove(levels, removeIdx);
}
private List<float> SeriesToWorkWith(List<float> timeseries,
int beginIndex, int endIndex)
{
if ((beginIndex == 0) && (endIndex == timeseries.Count))
return timeseries;
return timeseries.GetRange(beginIndex, endIndex);
}
}