@@ -80,7 +80,7 @@ def __init__(self, name, period):
8080
8181 protected override IndicatorBase < IBaseData > CreateIndicator ( )
8282 {
83- return new PythonIndicator ( CreatePythonIndicator ( ) , false ) ;
83+ return new PythonIndicator ( CreatePythonIndicator ( ) ) ;
8484 }
8585
8686 protected override string TestFileName => "spy_with_indicators.txt" ;
@@ -362,7 +362,7 @@ def Update(self, input):
362362 ) ;
363363 var pythonIndicator = module . GetAttr ( "CustomSimpleMovingAverage" )
364364 . Invoke ( "custom" . ToPython ( ) , 14 . ToPython ( ) ) ;
365- var SMAWithWarmUpPeriod = new PythonIndicator ( pythonIndicator , false ) ;
365+ var SMAWithWarmUpPeriod = new PythonIndicator ( pythonIndicator ) ;
366366 var reference = new DateTime ( 2000 , 1 , 1 , 0 , 0 , 0 ) ;
367367 var period = ( ( IIndicatorWarmUpPeriodProvider ) SMAWithWarmUpPeriod ) . WarmUpPeriod ;
368368
@@ -404,7 +404,7 @@ def Update(self, input):
404404 ) ;
405405 var pythonIndicator = module . GetAttr ( "CustomSimpleMovingAverage" )
406406 . Invoke ( "custom" . ToPython ( ) , 14 . ToPython ( ) ) ;
407- var indicator = new PythonIndicator ( pythonIndicator , false ) ;
407+ var indicator = new PythonIndicator ( pythonIndicator ) ;
408408
409409 Assert . AreEqual ( 0 , indicator . WarmUpPeriod ) ;
410410 }
@@ -421,7 +421,7 @@ public void PythonIndicatorDoesntRequireWrappingToWork()
421421 using ( Py . GIL ( ) )
422422 {
423423 using dynamic customSma = CreatePythonIndicator ( period ) ;
424- var wrapper = new PythonIndicator ( customSma , false ) ;
424+ var wrapper = new PythonIndicator ( customSma ) ;
425425
426426 for ( int i = 0 ; i < data . Length ; i ++ )
427427 {
@@ -513,5 +513,76 @@ public override void AcceptsRenkoBarsAsInput()
513513 public override void AcceptsVolumeRenkoBarsAsInput ( )
514514 {
515515 }
516+
517+ [ Test ]
518+ public void UpdatedEventFiresCorrectlyWithCustomPythonIndicator ( )
519+ {
520+ using ( Py . GIL ( ) )
521+ {
522+ var module = PyModule . FromString (
523+ Guid . NewGuid ( ) . ToString ( ) ,
524+ $@ "
525+ from AlgorithmImports import *
526+ from collections import deque
527+
528+ class CustomSimpleMovingAverage(PythonIndicator):
529+ def __init__(self, name, period):
530+ super().__init__(self)
531+ self.name = name
532+ self.value = 0
533+ self.period = period
534+ self.warm_up_period = period
535+ self.queue = deque(maxlen=period)
536+
537+ @property
538+ def is_ready(self):
539+ return len(self.queue) >= self.period
540+
541+ # compute_next_value method is mandatory
542+ def compute_next_value(self, input):
543+ self.queue.appendleft(input.Value)
544+ count = len(self.queue)
545+ self.value = np.sum(self.queue) / count
546+ return self.value
547+
548+ class IndicatorUpdater:
549+ def __init__(self, period=3):
550+ self.count = 0
551+ self.indicator = CustomSimpleMovingAverage('SMA', period)
552+ self.indicator.updated += self._on_update
553+
554+ def _on_update(self, sender, consolidated):
555+ self.count += 1
556+
557+ def update_indicator(self):
558+ bar1 = TradeBar()
559+ bar1.value = 1
560+ bar2 = TradeBar()
561+ bar2.value = 2
562+ bar3 = TradeBar()
563+ bar3.value = 3
564+ bar4 = TradeBar()
565+ bar4.value = 4
566+ self.indicator.update(bar1)
567+ self.indicator.update(bar2)
568+ self.indicator.update(bar3)
569+ self.indicator.update(bar4)
570+
571+ def get_indicator_status(self):
572+ return self.indicator.is_ready
573+ "
574+ ) ;
575+ var period = 3 ;
576+ dynamic updater = module . GetAttr ( "IndicatorUpdater" )
577+ . Invoke ( period . ToPython ( ) ) ;
578+ updater . update_indicator ( ) ;
579+ var count = updater . count . As < int > ( ) ;
580+ var isReady = updater . get_indicator_status ( ) . As < bool > ( ) ;
581+ var indicatorValue = updater . indicator . value . As < decimal > ( ) ;
582+ Assert . AreEqual ( 4 , count ) ;
583+ Assert . IsTrue ( isReady ) ;
584+ Assert . AreEqual ( 3.0m , indicatorValue ) ;
585+ }
586+ }
516587 }
517588}
0 commit comments