chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,302 @@
|
||||
#
|
||||
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from clr import AddReference
|
||||
AddReference("QuantConnect.Indicators")
|
||||
|
||||
from QuantConnect.Indicators import *
|
||||
from datetime import datetime
|
||||
import decimal as d
|
||||
import unittest
|
||||
|
||||
class IndicatorExtensionsTests(unittest.TestCase):
|
||||
def test_PipesDataUsingOfFromFirstToSecond(self):
|
||||
first = SimpleMovingAverage(2)
|
||||
second = Delay(1)
|
||||
|
||||
# this is a configuration step, but returns the reference to the second for method chaining
|
||||
third = IndicatorExtensions.Of(second, first)
|
||||
|
||||
data1 = IndicatorDataPoint(datetime.now(), 1)
|
||||
data2 = IndicatorDataPoint(datetime.now(), 2)
|
||||
data3 = IndicatorDataPoint(datetime.now(), 3)
|
||||
data4 = IndicatorDataPoint(datetime.now(), 4)
|
||||
|
||||
# sma has one item
|
||||
first.Update(data1)
|
||||
self.assertFalse(first.IsReady)
|
||||
self.assertEqual(0, second.Current.Value)
|
||||
|
||||
# sma is ready, delay will repeat this value
|
||||
first.Update(data2)
|
||||
self.assertTrue(first.IsReady)
|
||||
self.assertFalse(second.IsReady)
|
||||
self.assertEqual(1.5, second.Current.Value)
|
||||
|
||||
# delay is ready, and repeats its first input
|
||||
first.Update(data3)
|
||||
self.assertTrue(second.IsReady)
|
||||
self.assertEqual(1.5, second.Current.Value)
|
||||
|
||||
# now getting the delayed data
|
||||
first.Update(data4)
|
||||
self.assertEqual(2.5, second.Current.Value)
|
||||
|
||||
def test_PipesDataFirstWeightedBySecond(self):
|
||||
period = 4
|
||||
value = Identity("Value")
|
||||
weight = Identity("Weight")
|
||||
|
||||
third = IndicatorExtensions.WeightedBy(value, weight, period)
|
||||
|
||||
data = range(1, 11)
|
||||
window = list(reversed(data))[:period]
|
||||
current = sum([ 2 * x * x for x in window ]) / float(sum(window))
|
||||
|
||||
for item in data:
|
||||
value.Update(datetime.now(), 2 * item)
|
||||
weight.Update(datetime.now(), item)
|
||||
|
||||
self.assertEqual(current, float(third.Current.Value))
|
||||
|
||||
def test_NewDataPushesToDerivedIndicators(self):
|
||||
identity = Identity("identity")
|
||||
self.sma = SimpleMovingAverage(3)
|
||||
|
||||
identity.Updated += self.identity_updated
|
||||
|
||||
identity.Update(datetime.now(), 1)
|
||||
identity.Update(datetime.now(), 2)
|
||||
self.assertFalse(self.sma.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 3)
|
||||
self.assertTrue(self.sma.IsReady)
|
||||
self.assertEqual(2, self.sma.Current.Value)
|
||||
|
||||
def identity_updated(self, sender, consolidated):
|
||||
self.sma.Update(consolidated)
|
||||
|
||||
def test_MultiChainSMA(self):
|
||||
identity = Identity("identity")
|
||||
delay = Delay(2)
|
||||
|
||||
# create the SMA of the delay of the identity
|
||||
sma = IndicatorExtensions.SMA(IndicatorExtensions.Of(delay, identity), 2)
|
||||
|
||||
identity.Update(datetime.now(), 1)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(sma.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 2)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(sma.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 3)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertFalse(sma.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 4)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertTrue(sma.IsReady)
|
||||
|
||||
self.assertEqual(1.5, sma.Current.Value)
|
||||
|
||||
def test_MultiChainEMA(self):
|
||||
identity = Identity("identity")
|
||||
delay = Delay(2)
|
||||
|
||||
# create the EMA of chained methods
|
||||
ema = IndicatorExtensions.EMA(IndicatorExtensions.Of(delay, identity), 2, d.Decimal(1))
|
||||
|
||||
identity.Update(datetime.now(), 1)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(ema.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 2)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(ema.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 3)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertFalse(ema.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 4)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertTrue(ema.IsReady)
|
||||
|
||||
self.assertEqual(2, ema.Current.Value)
|
||||
|
||||
def test_MultiChainMAX(self):
|
||||
identity = Identity("identity")
|
||||
delay = Delay(2)
|
||||
|
||||
# create the MAX of the delay of the identity
|
||||
max = IndicatorExtensions.MAX(IndicatorExtensions.Of(delay, identity), 2)
|
||||
|
||||
identity.Update(datetime.now(), 1)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(max.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 2)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(max.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 3)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertFalse(max.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 4)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertTrue(max.IsReady)
|
||||
|
||||
self.assertEqual(2, max.Current.Value)
|
||||
|
||||
def test_MultiChainMIN(self):
|
||||
identity = Identity("identity")
|
||||
delay = Delay(2)
|
||||
|
||||
# create the MAX of the delay of the identity
|
||||
min = IndicatorExtensions.MIN(IndicatorExtensions.Of(delay, identity), 2)
|
||||
|
||||
identity.Update(datetime.now(), 1)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(min.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 2)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertFalse(delay.IsReady)
|
||||
self.assertFalse(min.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 3)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertFalse(min.IsReady)
|
||||
|
||||
identity.Update(datetime.now(), 4)
|
||||
self.assertTrue(identity.IsReady)
|
||||
self.assertTrue(delay.IsReady)
|
||||
self.assertTrue(min.IsReady)
|
||||
|
||||
self.assertEqual(1, min.Current.Value)
|
||||
|
||||
def test_PlusAddsLeftAndRightAfterBothUpdated(self):
|
||||
left = Identity("left")
|
||||
right = Identity("right")
|
||||
composite = IndicatorExtensions.Plus(left, right)
|
||||
|
||||
left.Update(datetime.now(), 1)
|
||||
right.Update(datetime.now(), 1)
|
||||
self.assertEqual(2, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 2)
|
||||
self.assertEqual(2, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 3)
|
||||
self.assertEqual(2, composite.Current.Value)
|
||||
|
||||
right.Update(datetime.today(), 4)
|
||||
self.assertEqual(7, composite.Current.Value)
|
||||
|
||||
def test_MinusSubtractsLeftAndRightAfterBothUpdated(self):
|
||||
left = Identity("left")
|
||||
right = Identity("right")
|
||||
composite = IndicatorExtensions.Minus(left, right)
|
||||
|
||||
left.Update(datetime.today(), 1)
|
||||
right.Update(datetime.today(), 1)
|
||||
self.assertEqual(0, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 2)
|
||||
self.assertEqual(0, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 3)
|
||||
self.assertEqual(0, composite.Current.Value)
|
||||
|
||||
right.Update(datetime.today(), 4)
|
||||
self.assertEqual(-1, composite.Current.Value)
|
||||
|
||||
def test_OverDivdesLeftAndRightAfterBothUpdated(self):
|
||||
left = Identity("left")
|
||||
right = Identity("right")
|
||||
composite = IndicatorExtensions.Over(left, right)
|
||||
|
||||
left.Update(datetime.today(), 1)
|
||||
right.Update(datetime.today(), 1)
|
||||
self.assertEqual(1, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 2)
|
||||
self.assertEqual(1, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 3)
|
||||
self.assertEqual(1, composite.Current.Value)
|
||||
|
||||
right.Update(datetime.today(), 4)
|
||||
self.assertEqual(3.0 / 4.0, composite.Current.Value)
|
||||
|
||||
def test_OverHandlesDivideByZero(self):
|
||||
left = Identity("left")
|
||||
right = Identity("right")
|
||||
composite = IndicatorExtensions.Over(left, right)
|
||||
self.updatedEventFired = False
|
||||
composite.Updated += self.composite_updated
|
||||
|
||||
left.Update(datetime.today(), 1)
|
||||
self.assertFalse(self.updatedEventFired)
|
||||
right.Update(datetime.today(), 0)
|
||||
self.assertFalse(self.updatedEventFired)
|
||||
|
||||
# submitting another update to right won't cause an update without corresponding update to left
|
||||
right.Update(datetime.today(), 1)
|
||||
self.assertFalse(self.updatedEventFired)
|
||||
left.Update(datetime.today(), 1)
|
||||
self.assertTrue(self.updatedEventFired)
|
||||
|
||||
def composite_updated(self, sender, consolidated):
|
||||
self.updatedEventFired = True
|
||||
|
||||
def test_TimesMultipliesLeftAndRightAfterBothUpdated(self):
|
||||
left = Identity("left")
|
||||
right = Identity("right")
|
||||
composite = IndicatorExtensions.Times(left, right)
|
||||
|
||||
left.Update(datetime.today(), 1)
|
||||
right.Update(datetime.today(), 1)
|
||||
self.assertEqual(1, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 2)
|
||||
self.assertEqual(1, composite.Current.Value)
|
||||
|
||||
left.Update(datetime.today(), 3)
|
||||
self.assertEqual(1, composite.Current.Value)
|
||||
|
||||
right.Update(datetime.today(), 4)
|
||||
self.assertEqual(12, composite.Current.Value)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user