Passed
Push — master ( 34c628...b145a0 )
by Alec
02:16
created

DataOHLCV::addOHLCV()   A

Complexity

Conditions 6
Paths 9

Size

Total Lines 30
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 30
ccs 15
cts 15
cp 1
rs 9.1111
c 0
b 0
f 0
cc 6
nc 9
nop 8
crap 6

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * User: alec
4
 * Date: 31.10.18
5
 * Time: 15:20
6
 */
7
declare(strict_types=1);
8
9
namespace AlecRabbit;
10
11
use BCMathExtended\BC;
12
13
class DataOHLCV
14
{
15
    protected const DEFAULT_PERIOD_MULTIPLIER = 3;
16
    protected const MAX_PERIOD_MULTIPLIER = 100;
17
    protected const DEFAULT_SIZE = 500;
18
    protected const MAX_SIZE = 1440;
19
    protected const MIN_SIZE = 10;
20
    protected const RESOLUTIONS = RESOLUTIONS;
21
22
    /** @var array */
23
    protected $current;
24
    protected $timestamps = [];
25
    protected $opens = [];
26
    protected $highs = [];
27
    protected $lows = [];
28
    protected $closes = [];
29
    protected $volumes = [];
30
    protected $proxies = [];
31
32
    /** @var int */
33
    private $size;
34
    /** @var int */
35
    private $coefficient;
36
    /** @var string */
37
    private $pair;
38
39
    /**
40
     * DataOHLCV constructor.
41
     * @param string $pair
42
     * @param integer $size
43
     * @param int $coefficient
44
     */
45 98
    public function __construct(string $pair, ?int $size = null, int $coefficient = 1)
46
    {
47 98
        $this->size =
48 98
            (int)bounds(
49 98
                $size ?? static::DEFAULT_SIZE,
50 98
                static::MIN_SIZE,
51 98
                static::MAX_SIZE
52
            );
53 98
        $this->pair = $pair;
54 98
        $this->coefficient = $coefficient;
55 98
    }
56
57
    /**
58
     * @return int
59
     */
60 9
    public function getSize(): int
61
    {
62 9
        return $this->size;
63
    }
64
65 1
    public function hasPeriods(int $resolution, int $periods, int $multiplier = null): bool
66
    {
67
        $multiplier =
68 1
            (int)bounds($multiplier ?? self::DEFAULT_PERIOD_MULTIPLIER, 1, self::MAX_PERIOD_MULTIPLIER);
69
70
        return
71 1
            isset($this->timestamps[$resolution])
72 1
            && (\count($this->timestamps[$resolution]) >= ($periods * $multiplier));
73
    }
74
75 14
    public function addTrade(int $timestamp, int $side, float $price, float $amount): void
76
    {
77 14
        $this->addOHLCV($timestamp, $price, $price, $price, $price, $amount, $side);
78 14
    }
79
80 14
    public function addOHLCV(
81
        int $timestamp,
82
        float $open,
83
        float $high,
84
        float $low,
85
        float $close,
86
        float $volume,
87
        int $side,
88
        int $resolution = RESOLUTION_01MIN
89
    ): void {
90 14
        $ts = base_timestamp($timestamp, $resolution);
91 14
        if (isset($this->current[$resolution])) {
92 14
            if ($ts > $this->current[$resolution]['timestamp']) {
93 14
                $this->updateLast($resolution);
94 14
                $this->setCurrent($resolution, $ts, $open, $high, $low, $close, $volume);
95 14
            } elseif ($ts === $this->current[$resolution]['timestamp']) {
96 14
                $this->updateCurrent($resolution, $high, $low, $close, $volume);
97 1
            } elseif ($ts < $this->current[$resolution]['timestamp']) {
98 1
                throw new \RuntimeException(
99
                    'Incoming data are in unsorted order. Current timestamp is greater then incoming data\'s.' .
100 1
                    ' (' . $ts . ' < ' . $this->current[$resolution]['timestamp'] . ')'
101
                );
102
            }
103 14
            $this->trim($resolution);
104
        } else {
105 14
            $this->setCurrent($resolution, $ts, $open, $high, $low, $close, $volume);
106
        }
107
108 14
        if ($nextResolution = $this->nextResolution($resolution)) {
109 14
            $this->addOHLCV($timestamp, $open, $high, $low, $close, $volume, $side, $nextResolution);
110
        }
111 14
    }
112
113 14
    private function updateLast(int $resolution): void
114
    {
115 14
        $this->timestamps[$resolution][] = $this->current[$resolution]['timestamp'];
116 14
        $this->opens[$resolution][] = $this->current[$resolution]['opens'];
117 14
        $this->highs[$resolution][] = $this->current[$resolution]['high'];
118 14
        $this->lows[$resolution][] = $this->current[$resolution]['low'];
119 14
        $this->closes[$resolution][] = $this->current[$resolution]['close'];
120 14
        $this->volumes[$resolution][] = $this->current[$resolution]['volume'];
121 14
    }
122
123 14
    private function setCurrent(
124
        int $resolution,
125
        int $timestamp,
126
        float $open,
127
        float $high,
128
        float $low,
129
        float $close,
130
        float $volume
131
    ): void {
132 14
        $this->current[$resolution]['timestamp'] = $timestamp;
133 14
        $this->current[$resolution]['opens'] = $open;
134 14
        $this->current[$resolution]['high'] = $high;
135 14
        $this->current[$resolution]['low'] = $low;
136 14
        $this->current[$resolution]['close'] = $close;
137 14
        $this->current[$resolution]['volume'] = $volume;
138 14
    }
139
140 14
    private function updateCurrent(
141
        int $resolution,
142
        float $high,
143
        float $low,
144
        float $close,
145
        float $volume
146
    ): void {
147 14
        if ($high > $this->current[$resolution]['high']) {
148 12
            $this->current[$resolution]['high'] = $high;
149
        }
150 14
        if ($low < $this->current[$resolution]['low']) {
151 13
            $this->current[$resolution]['low'] = $low;
152
        }
153
154 14
        $this->current[$resolution]['close'] = $close;
155 14
        $this->current[$resolution]['volume'] =
156 14
            (float)BC::add((string)$this->current[$resolution]['volume'], (string)$volume, NORMAL_SCALE);
157 14
    }
158
159 14
    private function trim(int $resolution): void
160
    {
161 14
        if (isset($this->timestamps[$resolution]) && (\count($this->timestamps[$resolution]) > $this->size)) {
162 1
            unset_first($this->timestamps[$resolution]);
163 1
            unset_first($this->opens[$resolution]);
164 1
            unset_first($this->highs[$resolution]);
165 1
            unset_first($this->lows[$resolution]);
166 1
            unset_first($this->closes[$resolution]);
167 1
            unset_first($this->volumes[$resolution]);
168
        }
169 14
    }
170
171 25
    private function nextResolution($resolution): ?int
172
    {
173 25
        $key = array_search($resolution, static::RESOLUTIONS, true);
174 25
        if ($key !== false && array_key_exists(++$key, static::RESOLUTIONS)) {
175 24
            return static::RESOLUTIONS[$key];
176
        }
177 15
        return null;
178
    }
179
180
    /**
181
     * @param int $resolution
182
     * @return array
183
     */
184 11
    public function getTimestamps(int $resolution): array
185
    {
186
        return
187 11
            $this->timestamps[$resolution] ?? [];
188
    }
189
190
    /**
191
     * @param int $resolution
192
     * @param bool $useCoefficient
193
     * @return array
194
     */
195 1
    public function getOpens(int $resolution, bool $useCoefficient = false): array
196
    {
197
        return
198 1
            $this->mulArr(
199 1
                $this->opens[$resolution] ?? [],
200 1
                $useCoefficient
201
            );
202
    }
203
204 4
    private function mulArr(array $values, bool $useCoefficient): array
205
    {
206 4
        if ($useCoefficient && $this->coefficient !== 1) {
207 1
            $values = array_map(
208
                function ($v) {
209
                    return
210 1
                        $v * $this->coefficient;
211 1
                },
212 1
                $values
213
            );
214
        }
215
216 4
        return $values;
217
    }
218
219
    /**
220
     * @param int $resolution
221
     * @param bool $useCoefficient
222
     * @return array
223
     */
224 1
    public function getHighs(int $resolution, bool $useCoefficient = false): array
225
    {
226
        return
227 1
            $this->mulArr(
228 1
                $this->highs[$resolution] ?? [],
229 1
                $useCoefficient
230
            );
231
    }
232
233
    /**
234
     * @param int $resolution
235
     * @param bool $useCoefficient
236
     * @return null|float
237
     */
238 1
    public function getLastHigh(int $resolution, bool $useCoefficient = false): ?float
239
    {
240
        return
241 1
            $this->lastElement($this->highs[$resolution] ?? [], $useCoefficient);
242
    }
243
244
    /**
245
     * @param array $element
246
     * @param bool $useCoefficient
247
     * @return null|float
248
     */
249 1
    private function lastElement(array $element, bool $useCoefficient = false): ?float
250
    {
251 1
        if (false !== $lastElement = end($element)) {
252
            return
253 1
                $this->mul(
254 1
                    $lastElement,
255 1
                    $useCoefficient
256
                );
257
        }
258 1
        return null;
259
    }
260
261 6
    private function mul(float $value, bool $useCoefficient): float
262
    {
263 6
        if ($useCoefficient && $this->coefficient !== 1) {
264 2
            $value *= $this->coefficient;
265
        }
266 6
        return $value;
267
    }
268
269
    /**
270
     * @param int $resolution
271
     * @param bool $useCoefficient
272
     * @return array
273
     */
274 1
    public function getLows(int $resolution, bool $useCoefficient = false): array
275
    {
276
        return
277 1
            $this->mulArr(
278 1
                $this->lows[$resolution] ?? [],
279 1
                $useCoefficient
280
            );
281
    }
282
283
    /**
284
     * @param int $resolution
285
     * @param bool $useCoefficient
286
     * @return null|float
287
     */
288 1
    public function getLastLow(int $resolution, bool $useCoefficient = false): ?float
289
    {
290
        return
291 1
            $this->lastElement($this->lows[$resolution] ?? [], $useCoefficient);
292
    }
293
294
    /**
295
     * @param int $resolution
296
     * @param bool $useCoefficient
297
     * @return array
298
     */
299 1
    public function getCloses(int $resolution, bool $useCoefficient = false): array
300
    {
301
        return
302 1
            $this->mulArr(
303 1
                $this->closes[$resolution] ?? [],
304 1
                $useCoefficient
305
            );
306
    }
307
308
    /**
309
     * @param int $resolution
310
     * @param bool $useCoefficient
311
     * @return null|float
312
     */
313 1
    public function getLastClose(int $resolution, bool $useCoefficient = false): ?float
314
    {
315
        return
316 1
            $this->lastElement($this->closes[$resolution] ?? [], $useCoefficient);
317
    }
318
319
    /**
320
     * @param int $resolution
321
     * @return array
322
     */
323 1
    public function getVolumes(int $resolution): array
324
    {
325
        return
326 1
            $this->volumes[$resolution] ?? [];
327
    }
328
329
    /**
330
     * @codeCoverageIgnore
331
     */
332
    public function dump(): void
333
    {
334
        if (\defined('APP_DEBUG') && APP_DEBUG) {
335
            $result = [];
336
            $pair = $this->getPair();
337
            foreach (static::RESOLUTIONS as $resolution) {
338
                $count = \count($this->timestamps[$resolution] ?? []);
339
                $result[] =
340
                    sprintf(
341
                        '%s [%s] %s %s %s %s %s %s %s',
342
                        $this->current[$resolution]['timestamp'],
343
                        RESOLUTION_ALIASES[$resolution],
344
                        $count,
345
                        $pair,
346
                        $this->current[$resolution]['opens'],
347
                        $this->current[$resolution]['high'],
348
                        $this->current[$resolution]['low'],
349
                        $this->current[$resolution]['close'],
350
                        $this->current[$resolution]['volume']
351
                    );
352
            }
353
            dump($result);
354
        }
355
    }
356
357
    /**
358
     * @return string
359
     */
360 57
    public function getPair(): string
361
    {
362 57
        return $this->pair;
363
    }
364
}
365