@@ -378,6 +378,37 @@ def _construct_candlestick_collections(dates, opens, highs, lows, closes, market
378
378
def _construct_renko_collections (dates , highs , lows , volumes , config_renko_params , closes , marketcolors = None ):
379
379
"""Represent the price change with bricks
380
380
381
+ NOTE: this code assumes if any value open, low, high, close is
382
+ missing they all are missing
383
+
384
+ Algorithm Explanation
385
+ ---------------------
386
+ In the first part of the algorithm, we populate the cdiff array
387
+ along with adjusting the dates and volumes arrays into the new_dates and
388
+ new_volumes arrays. A single date includes a range from no bricks to many
389
+ bricks, if a date has no bricks it shall not be included in new_dates,
390
+ and if it has n bricks then it will be included n times. Volumes use a
391
+ volume cache to save volume amounts for dates that do not have any bricks
392
+ before adding the cache to the next date that has at least one brick.
393
+ We populate the cdiff array with each close values difference from the
394
+ previously created brick divided by the brick size.
395
+
396
+ In the second part of the algorithm, we iterate through the values in cdiff
397
+ and add 1s or -1s to the bricks array depending on whether the value is
398
+ positive or negative. Every time there is a trend change (ex. previous brick is
399
+ an upbrick, current brick is a down brick) we draw one less brick to account
400
+ for the price having to move the previous bricks amount before creating a
401
+ brick in the opposite direction.
402
+
403
+ In the final part of the algorithm, we enumerate through the bricks array and
404
+ assign up-colors or down-colors to the associated index in the color array and
405
+ populate the verts list with each bricks vertice to be used to create the matplotlib
406
+ PolyCollection.
407
+
408
+ Useful sources:
409
+ https://avilpage.com/2018/01/how-to-plot-renko-charts-with-python.html
410
+ https://school.stockcharts.com/doku.php?id=chart_analysis:renko
411
+
381
412
Parameters
382
413
----------
383
414
dates : sequence
@@ -413,12 +444,12 @@ def _construct_renko_collections(dates, highs, lows, volumes, config_renko_param
413
444
else :
414
445
brick_size = _calculate_atr (atr_length , highs , lows , closes )
415
446
else : # is an integer or float
416
- upper_limit = (max (closes ) - min (closes )) / 5
417
- lower_limit = ( max (closes ) - min ( closes )) / 32
447
+ upper_limit = (max (closes ) - min (closes )) / 2
448
+ lower_limit = 0.01 * _calculate_atr ( len (closes )- 1 , highs , lows , closes )
418
449
if brick_size > upper_limit :
419
- raise ValueError ("Specified brick_size may not be larger than (20 % of the close price range of the dataset) which has value: " + str (upper_limit ))
450
+ raise ValueError ("Specified brick_size may not be larger than (50 % of the close price range of the dataset) which has value: " + str (upper_limit ))
420
451
elif brick_size < lower_limit :
421
- raise ValueError ("Specified brick_size may not be smaller than (3.125% of the close price range of the dataset) which has value: " + str (lower_limit ))
452
+ raise ValueError ("Specified brick_size may not be smaller than (0.01* the Average True Value of the dataset) which has value: " + str (lower_limit ))
422
453
423
454
alpha = marketcolors ['alpha' ]
424
455
@@ -427,7 +458,7 @@ def _construct_renko_collections(dates, highs, lows, volumes, config_renko_param
427
458
euc = mcolors .to_rgba (marketcolors ['edge' ][ 'up' ], 1.0 )
428
459
edc = mcolors .to_rgba (marketcolors ['edge' ]['down' ], 1.0 )
429
460
430
- cdiff = []
461
+ cdiff = [] # holds the differences between each close and the previously created brick / the brick size
431
462
prev_close_brick = closes [0 ]
432
463
volume_cache = 0 # holds the volumes for the dates that were skipped
433
464
new_dates = [] # holds the dates corresponding with the index
@@ -447,7 +478,7 @@ def _construct_renko_collections(dates, highs, lows, volumes, config_renko_param
447
478
new_dates .extend ([dates [i ]] * abs (brick_diff ))
448
479
prev_close_brick += brick_diff * brick_size
449
480
450
- bricks = [] # holds bricks, 1 for down bricks, - 1 for up bricks
481
+ bricks = [] # holds bricks, - 1 for down bricks, 1 for up bricks
451
482
curr_price = closes [0 ]
452
483
453
484
last_diff_sign = 0 # direction the bricks were last going in -1 -> down, 1 -> up
@@ -511,6 +542,47 @@ def _construct_renko_collections(dates, highs, lows, volumes, config_renko_param
511
542
def _construct_pointnfig_collections (dates , highs , lows , volumes , config_pointnfig_params , closes , marketcolors = None ):
512
543
"""Represent the price change with Xs and Os
513
544
545
+ NOTE: this code assumes if any value open, low, high, close is
546
+ missing they all are missing
547
+
548
+ Algorithm Explanation
549
+ ---------------------
550
+ In the first part of the algorithm, we populate the boxes array
551
+ along with adjusting the dates and volumes arrays into the new_dates and
552
+ new_volumes arrays. A single date includes a range from no boxes to many
553
+ boxes, if a date has no boxes it shall not be included in new_dates,
554
+ and if it has n boxes then it will be included n times. Volumes use a
555
+ volume cache to save volume amounts for dates that do not have any boxes
556
+ before adding the cache to the next date that has at least one box.
557
+ We populate the boxes array with each close values difference from the
558
+ previously created brick divided by the box size.
559
+
560
+ The second part of the algorithm has a series of step. First we combine the
561
+ adjacent like signed values in the boxes array (ex. [-1, -2, 3, -4] -> [-3, 3, -4]).
562
+ Next we subtract 1 from the absolute value of each element in boxes except the
563
+ first to ensure every time there is a trend change (ex. previous box is
564
+ an X, current brick is a O) we draw one less box to account for the price
565
+ having to move the previous box's amount before creating a box in the
566
+ opposite direction. Next we adjust volume and dates to combine volume into
567
+ non 0 box indexes and to only use dates from non 0 box indexes. We then
568
+ remove all 0s from the boxes array and once again combine adjacent similarly
569
+ signed differences in boxes.
570
+
571
+ Lastly, we enumerate through the boxes to populate the line_seg and circle_patches
572
+ arrays. line_seg holds the / and \ line segments that make up an X and
573
+ circle_patches holds matplotlib.patches Ellipse objects for each O. We start
574
+ by filling an x and y array each iteration which contain the x and y
575
+ coordinates for each box in the column. Then for each coordinate pair in
576
+ x, y we add to either the line_seg array or the circle_patches array
577
+ depending on the value of sign for the current column (1 indicates
578
+ line_seg, -1 indicates circle_patches). The height of the boxes take
579
+ into account padding which separates each box by a small margin in
580
+ order to increase readability.
581
+
582
+ Useful sources:
583
+ https://stackoverflow.com/questions/8750648/point-and-figure-chart-with-matplotlib
584
+ https://www.investopedia.com/articles/technical/03/081303.asp
585
+
514
586
Parameters
515
587
----------
516
588
dates : sequence
@@ -546,12 +618,12 @@ def _construct_pointnfig_collections(dates, highs, lows, volumes, config_pointnf
546
618
else :
547
619
box_size = _calculate_atr (atr_length , highs , lows , closes )
548
620
else : # is an integer or float
549
- upper_limit = (max (closes ) - min (closes )) / 5
550
- lower_limit = ( max (closes ) - min ( closes )) / 32
621
+ upper_limit = (max (closes ) - min (closes )) / 2
622
+ lower_limit = 0.01 * _calculate_atr ( len (closes )- 1 , highs , lows , closes )
551
623
if box_size > upper_limit :
552
- raise ValueError ("Specified box_size may not be larger than (20 % of the close price range of the dataset) which has value: " + str (upper_limit ))
624
+ raise ValueError ("Specified box_size may not be larger than (50 % of the close price range of the dataset) which has value: " + str (upper_limit ))
553
625
elif box_size < lower_limit :
554
- raise ValueError ("Specified box_size may not be smaller than (3.125% of the close price range of the dataset) which has value: " + str (lower_limit ))
626
+ raise ValueError ("Specified box_size may not be smaller than (0.01* the Average True Value of the dataset) which has value: " + str (lower_limit ))
555
627
556
628
alpha = marketcolors ['alpha' ]
557
629
0 commit comments