Skip to content

Commit

Permalink
correlation coefficient (#14)
Browse files Browse the repository at this point in the history
* add Correlation Coefficient
  • Loading branch information
DaveSkender authored Jan 19, 2020
1 parent 130680b commit 0e34f6e
Show file tree
Hide file tree
Showing 10 changed files with 694 additions and 8 deletions.
8 changes: 4 additions & 4 deletions Indicators/Cci/Cci.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ public static IEnumerable<CciResult> GetCci(IEnumerable<Quote> history, int look
// roll through interim results to calculate CCI
foreach (CciResult result in results.Where(x => x.Index >= lookbackPeriod))
{
IEnumerable<CciResult> lookback = results.Where(x => x.Index <= result.Index && x.Index > (result.Index - lookbackPeriod));
IEnumerable<CciResult> period = results.Where(x => x.Index <= result.Index && x.Index > (result.Index - lookbackPeriod));

decimal smaTp = (decimal)lookback.Select(x => x.Tp).Average();
decimal smaTp = (decimal)period.Select(x => x.Tp).Average();
decimal meanDv = 0;

foreach (CciResult l in lookback)
foreach (CciResult p in period)
{
meanDv += Math.Abs(smaTp - (decimal)l.Tp);
meanDv += Math.Abs(smaTp - (decimal)p.Tp);
}
meanDv /= lookbackPeriod;
result.Cci = (result.Tp - smaTp) / ((decimal)0.015 * meanDv);
Expand Down
20 changes: 20 additions & 0 deletions Indicators/Correlation/Correlation.Models.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace Skender.Stock.Indicators
{

public class CorrResult
{
public int Index { get; set; }
public DateTime Date { get; set; }
public decimal? Correlation { get; set; }

// internal use only
internal decimal PriceA { get; set; }
internal decimal PriceB { get; set; }
internal decimal PriceA2 => PriceA * PriceA;
internal decimal PriceB2 => PriceB * PriceB;
internal decimal PriceAB => PriceA * PriceB;
}

}
63 changes: 63 additions & 0 deletions Indicators/Correlation/Correlation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Skender.Stock.Indicators
{
public static partial class Indicator
{
// CORRELATION (e.g. BETA when used with Indices)
public static IEnumerable<CorrResult> GetCorrelation(IEnumerable<Quote> historyA, IEnumerable<Quote> historyB, int lookbackPeriod)
{
// clean quotes
historyA = Cleaners.PrepareHistory(historyA);
historyB = Cleaners.PrepareHistory(historyB);

// initialize results
List<CorrResult> results = new List<CorrResult>();


// roll through history for interim data
foreach (Quote a in historyA)
{
Quote b = historyB.Where(x => x.Date == a.Date).FirstOrDefault();
if (b == null)
{
throw new BadHistoryException("Correlation requires matching dates in provided histories. {0} not found in historyB.");
}

CorrResult result = new CorrResult
{
Index = (int)a.Index,
Date = a.Date,
PriceA = a.Close,
PriceB = b.Close
// other values calculated in class properties
};
results.Add(result);
}

// compute correlation
foreach (CorrResult r in results.Where(x => x.Index >= lookbackPeriod))
{
IEnumerable<CorrResult> period = results.Where(x => x.Index > (r.Index - lookbackPeriod) && x.Index <= r.Index);

decimal avgA = period.Select(x => x.PriceA).Average();
decimal avgB = period.Select(x => x.PriceB).Average();
decimal avgA2 = period.Select(x => x.PriceA2).Average();
decimal avgB2 = period.Select(x => x.PriceB2).Average();
decimal avgAB = period.Select(x => x.PriceAB).Average();

decimal varianceA = avgA2 - avgA * avgA;
decimal varianceB = avgB2 - avgB * avgB;
decimal covariance = avgAB - avgA * avgB;

r.Correlation = covariance / (decimal)Math.Sqrt((double)(varianceA * varianceB));
}

return results;
}

}

}
53 changes: 53 additions & 0 deletions Indicators/Correlation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Correlation Coefficient (e.g Beta)

Correlation between two quote histories, based on Close price. This is `Beta` if one history represents the overall market.
[More info ...](https://school.stockcharts.com/doku.php?id=technical_indicators:correlation_coeffici)

``` C#
// usage
IEnumerable<CorrResult> results = Indicator.GetCorr(history, lookbackPeriod);
```

## Parameters

| name | type | notes
| -- |-- |--
| `historyA` | IEnumerable\<[Quote](/GUIDE.md#Quote)\> | Historical Quotes data should be at any consistent frequency (day, hour, minute, etc). You must supply at least `N` periods of `history`. The `A` history will be used to establish result length, so use the shorter history here.
| `historyB` | IEnumerable\<[Quote](/GUIDE.md#Quote)\> | Historical Quotes data should be at any consistent frequency (day, hour, minute, etc). You must supply at least `N` periods of `history`. Must at least the same date elements of `historyA`. Exception will be thrown if not matched.
| `lookbackPeriod` | int | Number of periods (`N`) in the lookback period.

## Response

``` C#
IEnumerable<CorrResult>
```

The first `N-1` periods will have `null` values since there's not enough data to calculate. We always return the same number of elements as there are in the historical quotes.

### CorrResult

| name | type | notes
| -- |-- |--
| `Index` | int | Sequence of dates
| `Date` | DateTime | Date
| `Corr` | decimal | Correlation based on `N` lookback periods

## Example

``` C#
// fetch historical quotes from your favorite feed, in Quote format
IEnumerable<Quote> historyTSLA = GetHistoryFromFeed("TSLA");
IEnumerable<Quote> historySPX = GetHistoryFromFeed("SPX");

// calculate 20-period Correlation
IEnumerable<CorrResult> results = Indicator.GetCorr(historySPX,historyTSLA,20);

// use results as needed
DateTime evalDate = DateTime.Parse("12/31/2018");
CorrResult result = results.Where(x=>x.Date==evalDate).FirstOrDefault();
Console.WriteLine("CORR(SPX,TSLA,20) on {0} was ${1}", result.Date, result.Corr);
```

``` text
CORR(SPX,TSLA,20) on 12/31/2018 was 0.85
```
8 changes: 4 additions & 4 deletions Indicators/StochasticRsi/StochRsi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public static IEnumerable<StochRsiResult> GetStochRsi(IEnumerable<Quote> history

if (h.Index >= 2 * lookbackPeriod)
{
IEnumerable<RsiResult> lookback = rsiResults.Where(x => x.Index <= h.Index && x.Index > (h.Index - lookbackPeriod));
float? rsi = lookback.Where(x => x.Index == h.Index).FirstOrDefault().Rsi;
float? rsiHigh = lookback.Select(x => x.Rsi).Max();
float? rsiLow = lookback.Select(x => x.Rsi).Min();
IEnumerable<RsiResult> period = rsiResults.Where(x => x.Index <= h.Index && x.Index > (h.Index - lookbackPeriod));
float? rsi = period.Where(x => x.Index == h.Index).FirstOrDefault().Rsi;
float? rsiHigh = period.Select(x => x.Rsi).Max();
float? rsiLow = period.Select(x => x.Rsi).Min();

result.StochRsi = (rsi - rsiLow) / (rsiHigh - rsiLow);
}
Expand Down
Loading

0 comments on commit 0e34f6e

Please sign in to comment.