generated from bennycode/ts-node-starter
-
-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(util): Calculate streaks (#725)
- Loading branch information
Showing
6 changed files
with
94 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import {getStreaks} from './getStreaks.js'; | ||
|
||
describe('getStreaks', () => { | ||
const input = [10, 20, 30, 40, 32, 42, 50, 45, 44, 41, 59, 90, 100]; | ||
|
||
describe('uptrends', () => { | ||
it('keeps track of upward streak lengths', () => { | ||
const actual = getStreaks(input, 'up'); | ||
expect(actual.map(s => s.length)).toStrictEqual([3, 2, 3]); | ||
}); | ||
|
||
it('keeps track of price increases during an upward streak', () => { | ||
const actual = getStreaks(input, 'up'); | ||
expect(actual.map(s => s.percentage)).toStrictEqual([300, 56.25, 143.90243902439025]); | ||
}); | ||
}); | ||
|
||
describe('downtrends', () => { | ||
it('keeps track of downward streak lengths', () => { | ||
const actual = getStreaks(input, 'down'); | ||
expect(actual.map(s => s.length)).toStrictEqual([1, 3]); | ||
}); | ||
|
||
it('keeps track of price decreases during a downward streak', () => { | ||
const actual = getStreaks(input, 'down'); | ||
expect(actual.map(s => s.percentage)).toStrictEqual([-20, -18]); | ||
}); | ||
}); | ||
|
||
describe('special cases', () => { | ||
it("doesn't record a streak of 1", () => { | ||
const actual = getStreaks([1], 'up'); | ||
expect(actual.map(s => s.length)).toStrictEqual([]); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
export type Streak = { | ||
/** Length of the streak */ | ||
length: number; | ||
/** Price change percentage during the streak */ | ||
percentage: number; | ||
}; | ||
|
||
/** | ||
* Tracks the lengths (streaks) of continuous price movements (up or down). | ||
* | ||
* @param prices A series of prices | ||
* @param keepSide If you want to receive only uptrends or downtrends | ||
* @returns An array of objects representing the filtered streaks | ||
*/ | ||
export function getStreaks(prices: number[], keepSide: 'up' | 'down'): Streak[] { | ||
const streaks: Streak[] = []; | ||
let currentStreak = 0; | ||
|
||
function saveStreak(i: number) { | ||
const endPrice = prices[i - 1]; | ||
const startPrice = prices[i - currentStreak - 1]; | ||
const percentage = ((endPrice - startPrice) / startPrice) * 100; | ||
streaks.push({length: currentStreak, percentage}); | ||
} | ||
|
||
for (let i = 1; i < prices.length; i++) { | ||
const isUpward = keepSide === 'up' && prices[i] > prices[i - 1]; | ||
const isDownward = keepSide === 'down' && prices[i] < prices[i - 1]; | ||
if (isUpward || isDownward) { | ||
currentStreak++; | ||
} else { | ||
// Save the streak if it ends | ||
if (currentStreak > 0) { | ||
saveStreak(i); | ||
} | ||
// Reset the streak | ||
currentStreak = 0; | ||
} | ||
} | ||
|
||
// Append the final streak if it exists | ||
if (currentStreak > 0) { | ||
saveStreak(prices.length); | ||
} | ||
|
||
return streaks; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters