| 1 | #!/usr/bin/env python |
|---|
| 2 | #-*- coding:utf-8 -*- |
|---|
| 3 | |
|---|
| 4 | import sys, os |
|---|
| 5 | # TREMOLO_PATH = os.path.split( os.path.dirname(__file__) )[0] |
|---|
| 6 | # if TREMOLO_PATH not in sys.path: sys.path.append(TREMOLO_PATH) |
|---|
| 7 | # from assets.foundation import Asset |
|---|
| 8 | from foundation import Indication |
|---|
| 9 | |
|---|
| 10 | class MovingAverage (Indication): |
|---|
| 11 | """ |
|---|
| 12 | すべての移動平均指標の基本となるクラスです. |
|---|
| 13 | """ |
|---|
| 14 | @classmethod |
|---|
| 15 | def isRealIndication(cls): return False |
|---|
| 16 | @classmethod |
|---|
| 17 | def getType(cls): return float |
|---|
| 18 | |
|---|
| 19 | def __init__(self, asset, parent=None): Indication.__init__(self, asset, parent) |
|---|
| 20 | |
|---|
| 21 | def getDescription(self): return "Indication::MovingAverage" |
|---|
| 22 | |
|---|
| 23 | def evaluate(self, t): raise NotImplementedError |
|---|
| 24 | |
|---|
| 25 | def getPreviousData(self, t, n=5): |
|---|
| 26 | """ |
|---|
| 27 | t時点からn回前までの複数のデータを取得し、リストで返します. |
|---|
| 28 | """ |
|---|
| 29 | self.asset.lock(t) |
|---|
| 30 | tp = self.asset.getType() |
|---|
| 31 | dat = [] |
|---|
| 32 | if tp == tuple: |
|---|
| 33 | dat = [self.asset.get(t-i)[0] for i in xrange(n)] |
|---|
| 34 | elif tp == int or tp == float: |
|---|
| 35 | dat = [self.asset.get(t-i) for i in xrange(n)] |
|---|
| 36 | self.asset.unlock() |
|---|
| 37 | return dat |
|---|
| 38 | |
|---|
| 39 | class SMA(MovingAverage): |
|---|
| 40 | """ |
|---|
| 41 | 単純移動平均を表すクラスです. |
|---|
| 42 | """ |
|---|
| 43 | @classmethod |
|---|
| 44 | def isRealIndication(cls): return True |
|---|
| 45 | |
|---|
| 46 | def __init__(self, asset, parent=None, length=5): |
|---|
| 47 | from scipy.ndimage.measurements import mean |
|---|
| 48 | MovingAverage.__init__(self, asset, parent) |
|---|
| 49 | if type(length) == int and length > 0: self.length = length |
|---|
| 50 | else: raise TypeError("the variable 'length' is not valid.") |
|---|
| 51 | |
|---|
| 52 | def getDescription(self): return "Indication::SimpleMovingAverage" |
|---|
| 53 | |
|---|
| 54 | def evaluate(self, t): |
|---|
| 55 | dat = self.getPreviousData(t, self.length) |
|---|
| 56 | return mean(dat) |
|---|
| 57 | |
|---|
| 58 | class WMA(MovingAverage): |
|---|
| 59 | """ |
|---|
| 60 | 加重移動平均を表すクラスです. |
|---|
| 61 | """ |
|---|
| 62 | @classmethod |
|---|
| 63 | def isRealIndication(cls): return True |
|---|
| 64 | |
|---|
| 65 | def __init__(self, asset, parent=None, length=5): |
|---|
| 66 | MovingAverage.__init__(self, asset, parent) |
|---|
| 67 | if type(length) == int and length > 0: |
|---|
| 68 | self.__length = length |
|---|
| 69 | self.__denominator = length*(length+1)/2.0 |
|---|
| 70 | self.__cache_list = [(length-i) for i in xrange(length)] |
|---|
| 71 | else: raise TypeError("the variable 'length' is not valid.") |
|---|
| 72 | |
|---|
| 73 | def getDescription(self): return "Indication::WeightedMovingAverage" |
|---|
| 74 | |
|---|
| 75 | def setLength(self, length): |
|---|
| 76 | if type(length) == int and length > 0: |
|---|
| 77 | self.__length = length |
|---|
| 78 | self.__denominator = length*(length+1)/2.0 |
|---|
| 79 | self.__cache_list = [(length-i) for i in xrange(length)] |
|---|
| 80 | else: raise TypeError("the variable 'length' is not valid.") |
|---|
| 81 | |
|---|
| 82 | def evaluate(self, t): |
|---|
| 83 | dat = self.getPreviousData(t, self.__length) |
|---|
| 84 | numerator = sum([x*dat[i] for (i, x) in enumerate(self.__cache_list)]) |
|---|
| 85 | return numerator / self.__denominator |
|---|
| 86 | |
|---|
| 87 | class EMA(MovingAverage): |
|---|
| 88 | """ |
|---|
| 89 | 指数加重移動平均を表すクラスです. |
|---|
| 90 | """ |
|---|
| 91 | @classmethod |
|---|
| 92 | def isRealIndication(cls): return True |
|---|
| 93 | |
|---|
| 94 | def getDescription(self): return "Indication::ExponentiallyWeightedMovingAverage" |
|---|
| 95 | |
|---|
| 96 | def __init__(self, asset, parent=None, length=5, alpha=-1, approximation=False): |
|---|
| 97 | """ |
|---|
| 98 | オブジェクトのコンストラクタです。 |
|---|
| 99 | |
|---|
| 100 | length : 過去に参照する長さの値 |
|---|
| 101 | alpha : 減衰率.0から1の間で指定.-1の場合は適切な値に設定される |
|---|
| 102 | approximation : 近似を行って計算を行うかどうか.デフォルトはFalse |
|---|
| 103 | """ |
|---|
| 104 | MovingAverage.__init__(self, asset, parent) |
|---|
| 105 | |
|---|
| 106 | if alpha == -1 or (type(alpha)==float and 0.0 < alpha < 1.0): |
|---|
| 107 | self.__alpha = alpha |
|---|
| 108 | else: raise TypeError("the variable 'alpha' is not valid.") |
|---|
| 109 | if type(length) == int and length > 0: |
|---|
| 110 | self.__length = length |
|---|
| 111 | else: raise TypeError("the variable 'length' is not valid.") |
|---|
| 112 | |
|---|
| 113 | self.__initCache() |
|---|
| 114 | self.approximation = approximation |
|---|
| 115 | |
|---|
| 116 | def __initCache(self): |
|---|
| 117 | k = self.__alpha == -1 and 2.0/(self.__length+1) or self.__alpha |
|---|
| 118 | oneMinusK = 1.0 - k |
|---|
| 119 | self.__cache_list = [(oneMinusK**i) for i in xrange(self.__length)] |
|---|
| 120 | |
|---|
| 121 | def setAlpha(self, alpha): |
|---|
| 122 | if alpha == -1 or (type(alpha)==float and 0.0 < alpha < 1.0): |
|---|
| 123 | self.__alpha = alpha |
|---|
| 124 | else: raise TypeError("the variable 'alpha' is not valid.") |
|---|
| 125 | self.__initCache() |
|---|
| 126 | |
|---|
| 127 | def setLength(self, length): |
|---|
| 128 | if type(length) == int and length > 0: |
|---|
| 129 | self.__length = length |
|---|
| 130 | else: raise TypeError("the variable 'length' is not valid.") |
|---|
| 131 | self.__initCache() |
|---|
| 132 | |
|---|
| 133 | def evaluate(self, t): |
|---|
| 134 | n = self.__length |
|---|
| 135 | dat = self.getPreviousData(t, n) |
|---|
| 136 | numerator = sum([x*dat[i] for (i, x) in enumerate(self.__cache_list)]) |
|---|
| 137 | if self.approximation: |
|---|
| 138 | denominator = 1.0/k |
|---|
| 139 | return numerator / denominator |
|---|
| 140 | else: |
|---|
| 141 | denominator = sum(self.__cache_list) |
|---|
| 142 | return numerator / denominator |
|---|