- public static getRandomFloatFluctuatedRounded(
- staticValue: number,
- fluctuationPercent: number,
- scale = 2
- ): number {
- if (fluctuationPercent === 0) {
- return Utils.roundTo(staticValue, scale);
+export const getRandomFloatFluctuatedRounded = (
+ staticValue: number,
+ fluctuationPercent: number,
+ scale = 2
+): number => {
+ if (fluctuationPercent < 0 || fluctuationPercent > 100) {
+ throw new RangeError(
+ `Fluctuation percent must be between 0 and 100. Actual value: ${fluctuationPercent}`
+ )
+ }
+ if (fluctuationPercent === 0) {
+ return roundTo(staticValue, scale)
+ }
+ const fluctuationRatio = fluctuationPercent / 100
+ return getRandomFloatRounded(
+ staticValue * (1 + fluctuationRatio),
+ staticValue * (1 - fluctuationRatio),
+ scale
+ )
+}
+
+export const extractTimeSeriesValues = (timeSeries: TimestampedData[]): number[] => {
+ return timeSeries.map(timeSeriesItem => timeSeriesItem.value)
+}
+
+type CloneableData =
+ | number
+ | string
+ | boolean
+ | null
+ | undefined
+ | Date
+ | CloneableData[]
+ | { [key: string]: CloneableData }
+
+type FormatKey = (key: string) => string
+
+const deepClone = <I extends CloneableData, O extends CloneableData = I>(
+ value: I,
+ formatKey?: FormatKey,
+ refs: Map<I, O> = new Map<I, O>()
+): O => {
+ const ref = refs.get(value)
+ if (ref !== undefined) {
+ return ref
+ }
+ if (Array.isArray(value)) {
+ const clone: CloneableData[] = []
+ refs.set(value, clone as O)
+ for (let i = 0; i < value.length; i++) {
+ clone[i] = deepClone(value[i], formatKey, refs)