class Pnl(PortfolioAnalyzer): Pnl = "Pnl" __slots__ = ('pnl_series', 'pnl') def __init__(self): super(Pnl, self).__init__() self.pnl_series = DataSeries(name=Pnl.Pnl, missing_value=0) self.pnl = 0 def update(self, time): if self.portfolio.performance_series.size() >= 2: self.pnl = self.portfolio.performance_series.get_by_idx( -1, 'total_equity') - self.portfolio.performance_series.get_by_idx( -2, 'total_equity') self.pnl_series.add({'timestamp': time, Pnl.Pnl: self.pnl}) def get_result(self): return {Pnl.Pnl: self.pnl} def get_series(self): return {Pnl.Pnl: self.pnl_series.get_series(Pnl.Pnl)} def id(self): return '%s.%s' % (self.portfolio.id(), Pnl.Pnl)
def setUp(self): self.time = 9000000000 self.simluation_clock = SimulationClock() self.simluation_clock.reset() self.simluation_clock.update_time(self.time) self.input = DataSeries() self.event_bus = BarAggregatorTest.DummyEventBus()
class Pnl(PortfolioAnalyzer): Pnl = "Pnl" __slots__ = ( 'pnl_series', 'pnl' ) def __init__(self): super(Pnl, self).__init__() self.pnl_series = DataSeries(name=Pnl.Pnl, missing_value=0) self.pnl = 0 def update(self, time): if self.portfolio.performance_series.size() >= 2: self.pnl = self.portfolio.performance_series.get_by_idx(-1, 'total_equity') - self.portfolio.performance_series.get_by_idx( -2, 'total_equity') self.pnl_series.add({'timestamp': time, Pnl.Pnl: self.pnl}) def get_result(self): return {Pnl.Pnl: self.pnl} def get_series(self): return {Pnl.Pnl: self.pnl_series.get_series(Pnl.Pnl)} def id(self): return '%s.%s' % (self.portfolio.id(), Pnl.Pnl)
def test_get_data(self): series = DataSeries() series.add({"timestamp": self.t1, "v1": 1, "v2": 1}) series.add({"timestamp": self.t2, "v1": 2, "v2": 2}) self.assertEqual([{'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 1}, {'name': "'None'", "timestamp": self.t2, "v1": 2, "v2": 2}], series.get_data())
def __create_series(self): close = DataSeries("close") t = self.t1 for idx, value in enumerate(self.values): close.add({"timestamp": t, "v1": value, "v2": value}) t = t + datetime.timedelta(0, 3) return close
def create_series_by_list(valuelist): close = DataSeries("close") t = datetime.datetime(2000, 1, 1, 11, 34, 59) for value in valuelist: close.add({"timestamp": t, "v1": value}) t = t + datetime.timedelta(0, 3) return close
def __init__(self): super(DrawDown, self).__init__() self.drawdown_series = DataSeries(name='DrawDown', missing_value=0) self.drawdown = 0 self.drawdown_pct = 0 self.high_equity = 0 self.low_equity = 0 self.current_run_up = 0 self.current_drawdown = 0
def get_name(indicator_name, inputs, input_key, *args): parts = [] parts.extend(DataSeries.convert_to_list(PipeLine.get_input_name(inputs))) if input_key: parts.extend(DataSeries.convert_to_list(input_key)) if args: parts.extend(args) content = ",".join(str(part) for part in parts) return '%s(%s)' % (indicator_name, content)
def __init__(self, name, inputs, input_keys, length=None, desc=None, **kwargs): super(PipeLine, self).__init__(name=name, keys=None, desc=desc, **kwargs) # f = lambda i: i \ # if isinstance(i, DataSeries) or isinstance(i, Indicator) \ # else inst_data_mgr.get_series(i) # if isinstance(inputs, list): # self.inputs = [f(i) for i in inputs] # else: # self.inputs = f(inputs) input_names = [] self.input_names_and_series = OrderedDict() if isinstance(inputs, list): for i in inputs: if isinstance(i, DataSeries): input_name = DataSeries.get_name(i) input_names.append(input_name) self.input_names_and_series[input_name] = i elif isinstance(i, Indicator): input_name = Indicator.get_name(i) input_names.append(input_name) self.input_names_and_series[input_name] = i elif isinstance(i, PipeLine): input_name = PipeLine.get_name(i) input_names.append(input_name) self.input_names_and_series[input_name] = i else: input_names.append(i) else: if isinstance(inputs, DataSeries): input_name = DataSeries.get_name(inputs) input_names.append(input_name) self.input_names_and_series[input_name] = inputs elif isinstance(inputs, Indicator): input_name = Indicator.get_name(inputs) input_names.append(input_name) self.input_names_and_series[input_name] = inputs elif isinstance(inputs, PipeLine): input_name = PipeLine.get_name(inputs) input_names.append(input_name) self.input_names_and_series[input_name] = inputs else: input_names.append(inputs) self.numPipes = len(input_names) self.length = length if length is not None else 1 self.input_names = input_names self.input_names_pos = dict(zip(input_names, range(len(input_names)))) self.input_keys = self._get_key(input_keys, None) # self.calculate = True self.__curr_timestamp = None self._flush_and_create() self.inputs = []
def test_init_w_keys(self): series = DataSeries(keys=set(["timestamp", "v1"])) series.add({"timestamp": self.t1, "v1": 1, "v2": 1}) result = series.get_data() self.assertEqual(1, len(result)) self.assertTrue("timestamp" in result[0]) self.assertTrue("v1" in result[0]) self.assertFalse("v2" in result[0])
def test_data_series(self, name, serializer): item = DataSeries("close", missing_value=0) t = datetime.datetime(2000, 1, 1, 11, 34, 59) values = [44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42, 45.84, 46.08, 45.89, 46.03, 45.61, 46.28, 46.28, 46.00] for idx, value in enumerate(values): item.add({"timestamp": t, "v1": value, "v2": value}) t = t + datetime.timedelta(0, 3) SerializerTest.ser_deser(name, serializer, item)
def __init__(self, portf_id="test", cash=1000000, analyzers=None): super(Portfolio, self).__init__() self.portf_id = portf_id self.ord_reqs = {} self.orders = {} self.performance_series = DataSeries("%s.Performance" % self.portf_id, missing_value=0) self.total_equity = 0 self.cash = cash self.stock_value = 0 self.analyzers = analyzers if analyzers is not None else [Pnl(), DrawDown()]
def create_random_walk_series(): close = DataSeries("close") t1 = datetime.datetime(2000, 1, 1, 11, 34, 59) t = t1 w = np.random.normal(0, 1, 1000) xs = 100 + np.cumsum(w) for value in xs: close.add({"timestamp": t, "v1": value, "v2": value}) t = t + datetime.timedelta(0, 3) return close
def test_size(self): series = DataSeries() self.assertEqual(0, series.size()) series.add({"timestamp": self.t1, "v1": 1}) self.assertEqual(1, series.size()) series.add({"timestamp": self.t2, "v1": 1}) self.assertEqual(2, series.size())
def test_init_w_data(self): data_list = [{"timestamp": self.t1, "v1": 1}, {"timestamp": self.t2, "v1": 2}] series = DataSeries(keys=set(["timestamp", "v1"]), data_list=data_list) self.assertEqual(2, series.size()) result = series.get_data() self.assertEqual(2, len(result)) self.assertEqual(1, result[0]["v1"]) self.assertEqual(2, result[1]["v1"])
def test_compare_against_oneoff_calculation(self): rw = np.cumsum(np.random.normal(0, 2, 1000)) + 100 close = DataSeries("close") close.start(self.app_context) t = datetime.datetime.now() sma = SMA(close, input_key='close', length=50) sma.start(self.app_context) result = [] for x in rw: close.add({"timestamp": t, "close": x}) result.append(sma.now('value')) t = t + datetime.timedelta(0, 3) result = np.array(result) # either apply or direct call is equivalent target = close.apply('close', start=None, end=None, func=talib.SMA, timeperiod=50) # target = talib.SMA(np.array(close.get_series('close')), timeperiod=50) result[np.isnan(result)] = 0 target[np.isnan(target)] = 0 try: np.testing.assert_almost_equal(target, result, 5) except AssertionError as e: self.fail(e.message)
def get_name(indicator_name, input, input_key, *args): if not input: return '%s' % indicator_name parts = [Indicator.get_input_name(input)] if input_key: parts.extend(DataSeries.convert_to_list(input_key)) if args: parts.extend(args) content = ",".join(str(part) for part in parts) return '%s(%s)' % (indicator_name, content)
def test_add(self): series = DataSeries() self.assertTrue(len(series.get_data()) == 0) series.add({"timestamp": self.t1, "v1": 1, "v2": 1}) series.add({"timestamp": self.t2, "v1": 2, "v2": 2}) self.assertEqual([{'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 1}, {'name': "'None'", "timestamp": self.t2, "v1": 2, "v2": 2}], series.get_data()) series.add({"timestamp": self.t2, "v1": 3, "v2": 3}) self.assertEqual([{'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 1}, {'name': "'None'", "timestamp": self.t2, "v1": 3, "v2": 3}], series.get_data()) series.add({"timestamp": self.t3, "v1": 4, "v2": 4}) self.assertEqual([{'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 1}, {'name': "'None'", "timestamp": self.t2, "v1": 3, "v2": 3}, {'name': "'None'", "timestamp": self.t3, "v1": 4, "v2": 4}], series.get_data())
def test_get_data_dict(self): series = DataSeries() series.add({"timestamp": self.t1, "v1": 1, "v2": 1}) series.add({"timestamp": self.t2, "v1": 2, "v2": 2}) self.assertEqual({'name': {str(self.t1): "'None'", str(self.t2): "'None'"}, "timestamp": {str(self.t1): self.t1, str(self.t2): self.t2}, "v1": {str(self.t1): 1, str(self.t2): 2}, "v2": {str(self.t1): 1, str(self.t2): 2}}, series.get_data_dict()) self.assertEqual({"v1": {str(self.t1): 1, str(self.t2): 2}, "v2": {str(self.t1): 1, str(self.t2): 2}}, series.get_data_dict(['v1', 'v2'])) self.assertEqual({str(self.t1): 1, str(self.t2): 2}, series.get_data_dict('v1'))
def __update_position_qty(self, time, cl_id, inst_id): pos = self.get_position(inst_id) qty = pos.filled_qty(cl_id) inst_id_str = str(inst_id) cl_id_str = str(cl_id) if cl_id_str in self.cl_position_qty_series_dict: pos_qty_series_dict = self.cl_position_qty_series_dict[cl_id_str] if inst_id_str in pos_qty_series_dict: pos_qty_series_dict[inst_id_str].add({ "timestamp": time, "qty": qty }) else: series = DataSeries("%s.PosQty" % inst_id, missing_value=0) series.add({"timestamp": time, "qty": qty}) pos_qty_series_dict[inst_id_str] = series else: pos_qty_series_dict = {} series = DataSeries("%s.PosQty" % inst_id, missing_value=0) series.add({"timestamp": time, "qty": qty}) pos_qty_series_dict[inst_id_str] = series self.cl_position_qty_series_dict[cl_id_str] = pos_qty_series_dict
def __update_position_qty(self, time, cl_id, inst_id): pos = self.get_position(inst_id) qty = pos.filled_qty(cl_id) inst_id_str = str(inst_id) cl_id_str = str(cl_id) if cl_id_str in self.cl_position_qty_series_dict: pos_qty_series_dict = self.cl_position_qty_series_dict[cl_id_str] if inst_id_str in pos_qty_series_dict: pos_qty_series_dict[inst_id_str].add({"timestamp": time, "qty": qty}) else: series = DataSeries("%s.PosQty" % inst_id, missing_value=0) series.add({"timestamp": time, "qty": qty}) pos_qty_series_dict[inst_id_str] = series else: pos_qty_series_dict = {} series = DataSeries("%s.PosQty" % inst_id, missing_value=0) series.add({"timestamp": time, "qty": qty}) pos_qty_series_dict[inst_id_str] = series self.cl_position_qty_series_dict[cl_id_str] = pos_qty_series_dict
def __init__(self): super(Pnl, self).__init__() self.pnl_series = DataSeries(name=Pnl.Pnl, missing_value=0) self.pnl = 0
def test_current_time(self): series = DataSeries() self.assertEqual(None, series.current_time()) series.add({"timestamp": self.t1, "v1": 1, "v2": 1}) self.assertEqual(self.t1, series.current_time()) series.add({"timestamp": self.t1, "v1": 1, "v2": 1}) self.assertEqual(self.t1, series.current_time()) series.add({"timestamp": self.t2, "v1": 2, "v2": 2}) self.assertEqual(self.t2, series.current_time())
else: rs = avg_gain / avg_loss rsi_value = 100 - 100 / (1 + rs) self.__prev_gain = avg_gain self.__prev_loss = avg_loss result[Indicator.VALUE] = rsi_value else: result[Indicator.VALUE] = np.nan self.add(result) if __name__ == "__main__": import datetime from algotrader.utils.time_series import DataSeries close = DataSeries("close") rsi = RSI(close, input_key='close', length=14) print rsi.name t = datetime.datetime.now() values = [44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42, 45.84, 46.08, 45.89, 46.03, 45.61, 46.28, 46.28, 46.00] for idx, value in enumerate(values): close.add({'timestamp': t, 'close': value}) t = t + datetime.timedelta(0, 3) print idx, rsi.now()
def test_ago(self): series = DataSeries() self.assertTrue(np.isnan(series.now())) series.add({"timestamp": self.t1, "v1": 1, "v2": 2}) self.assertEqual({'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 2}, series.ago(0)) series.add({"timestamp": self.t2, "v1": 1.2, "v2": 2.2}) self.assertEqual({'name': "'None'", "timestamp": self.t2, "v1": 1.2, "v2": 2.2}, series.ago(0)) self.assertEqual({'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 2}, series.ago(1)) series.add({"timestamp": self.t3, "v1": 1.3, "v2": 2.3}) self.assertEqual({'name': "'None'", "timestamp": self.t3, "v1": 1.3, "v2": 2.3}, series.ago(0)) self.assertEqual({'name': "'None'", "timestamp": self.t2, "v1": 1.2, "v2": 2.2}, series.ago(1)) self.assertEqual({'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 2}, series.ago(2)) series.add({"timestamp": self.t4, "v1": 1.4, "v2": 2.4}) self.assertEqual({'name': "'None'", "timestamp": self.t4, "v1": 1.4, "v2": 2.4}, series.ago(0)) self.assertEqual({'name': "'None'", "timestamp": self.t3, "v1": 1.3, "v2": 2.3}, series.ago(1)) self.assertEqual({'name': "'None'", "timestamp": self.t2, "v1": 1.2, "v2": 2.2}, series.ago(2)) self.assertEqual({'name': "'None'", "timestamp": self.t1, "v1": 1, "v2": 2}, series.ago(3)) self.assertEqual({"v1": 1.4, "v2": 2.4}, series.ago(0, ["v1", "v2"])) self.assertEqual(1.4, series.ago(0, "v1")) self.assertEqual(1.4, series.ago(0, ["v1"]))
class DrawDown(PortfolioAnalyzer): DrawDown = "DrawDown" DrawDownPct = "DrawDown%" HighEquity = "HighEquity" LowEquity = "LowEquity" CurrentRunUp = "CurrentRunUp" CurrentDrawDown = "CurrentDrawDown" __slots__ = ( 'drawdown_series', 'drawdown', 'drawdown_pct', 'high_equity', 'low_equity', 'current_run_up', 'current_drawdown', ) def __init__(self): super(DrawDown, self).__init__() self.drawdown_series = DataSeries(name='DrawDown', missing_value=0) self.drawdown = 0 self.drawdown_pct = 0 self.high_equity = 0 self.low_equity = 0 self.current_run_up = 0 self.current_drawdown = 0 def update(self, time): total_equity = self.portfolio.total_equity if self.portfolio.performance_series.size() == 1: self.low_equity = total_equity self.high_equity = total_equity else: if total_equity > self.high_equity: self.high_equity = total_equity self.low_equity = total_equity self.current_drawdown = 0 elif total_equity < self.low_equity: self.low_equity = total_equity self.current_run_up = 0 elif total_equity > self.low_equity and total_equity < self.high_equity: self.current_drawdown = 1 - total_equity / self.high_equity self.current_run_up = total_equity / self.low_equity - 1 if self.portfolio.performance_series.size() >= 2: self.drawdown = total_equity - self.high_equity if self.high_equity != 0: self.drawdown_pct = abs(self.drawdown / self.high_equity) self.drawdown_series.add({ 'timestamp': time, DrawDown.DrawDown: self.drawdown, DrawDown.DrawDownPct: self.drawdown_pct }) def get_result(self): return { DrawDown.DrawDown: self.drawdown, DrawDown.DrawDownPct: self.drawdown_pct, DrawDown.HighEquity: self.high_equity, DrawDown.LowEquity: self.low_equity, DrawDown.CurrentRunUp: self.current_run_up, DrawDown.CurrentDrawDown: self.current_drawdown } def get_series(self): return self.drawdown_series.get_series( [self.DrawDown, self.DrawDownPct]) def id(self): return '%s.%s' % (self.portfolio.id(), DrawDown.DrawDown)
def test_get_by_idx(self): series = DataSeries(keys=set(["timestamp", "v1", "v2"])) series.add({"timestamp": self.t1, "v1": 2}) series.add({"timestamp": self.t2, "v1": 2.4}) series.add({"timestamp": self.t2, "v2": 3.0}) # index and key self.assertEqual(2, series.get_by_idx(idx=0, keys="v1")) self.assertTrue(np.isnan(series.get_by_idx(idx=0, keys="v2"))) self.assertEqual(2.4, series.get_by_idx(idx=1, keys="v1")) self.assertEqual(3.0, series.get_by_idx(idx=1, keys="v2")) # index only self.assertEqual({"timestamp": self.t1, "v1": 2, "v2": np.nan}, series.get_by_idx(idx=0)) self.assertEqual({"timestamp": self.t2, "v1": 2.4, "v2": 3.0}, series.get_by_idx(idx=1)) # test index slice series2 = self.create_series_by_list(range(100)) sliced = series2.get_by_idx(keys='v1', idx=slice(-10,None,None)) self.assertEqual(len(sliced), 10) endPoint = series2.get_by_idx(keys='v1', idx=slice(-1, None, None)) self.assertEqual(endPoint[0], 99)
class DrawDown(PortfolioAnalyzer): DrawDown = "DrawDown" DrawDownPct = "DrawDown%" HighEquity = "HighEquity" LowEquity = "LowEquity" CurrentRunUp = "CurrentRunUp" CurrentDrawDown = "CurrentDrawDown" __slots__ = ( 'drawdown_series', 'drawdown', 'drawdown_pct', 'high_equity', 'low_equity', 'current_run_up', 'current_drawdown', ) def __init__(self): super(DrawDown, self).__init__() self.drawdown_series = DataSeries(name='DrawDown', missing_value=0) self.drawdown = 0 self.drawdown_pct = 0 self.high_equity = 0 self.low_equity = 0 self.current_run_up = 0 self.current_drawdown = 0 def update(self, time): total_equity = self.portfolio.total_equity if self.portfolio.performance_series.size() == 1: self.low_equity = total_equity self.high_equity = total_equity else: if total_equity > self.high_equity: self.high_equity = total_equity self.low_equity = total_equity self.current_drawdown = 0 elif total_equity < self.low_equity: self.low_equity = total_equity self.current_run_up = 0 elif total_equity > self.low_equity and total_equity < self.high_equity: self.current_drawdown = 1 - total_equity / self.high_equity self.current_run_up = total_equity / self.low_equity - 1 if self.portfolio.performance_series.size() >= 2: self.drawdown = total_equity - self.high_equity if self.high_equity != 0: self.drawdown_pct = abs(self.drawdown / self.high_equity) self.drawdown_series.add({'timestamp': time, DrawDown.DrawDown: self.drawdown, DrawDown.DrawDownPct: self.drawdown_pct}) def get_result(self): return {DrawDown.DrawDown: self.drawdown, DrawDown.DrawDownPct: self.drawdown_pct, DrawDown.HighEquity: self.high_equity, DrawDown.LowEquity: self.low_equity, DrawDown.CurrentRunUp: self.current_run_up, DrawDown.CurrentDrawDown: self.current_drawdown} def get_series(self): return self.drawdown_series.get_series([self.DrawDown, self.DrawDownPct]) def id(self): return '%s.%s' % (self.portfolio.id(), DrawDown.DrawDown)
def test_get_by_time(self): series = DataSeries(keys=set(["timestamp", "v1", "v2"])) # time and key series.add({"timestamp": self.t1, "v1": 2}) series.add({"timestamp": self.t2, "v1": 2.4}) series.add({"timestamp": self.t2, "v2": 3.0}) self.assertEqual(2, series.get_by_time(time=self.t1, keys="v1")) self.assertTrue(np.isnan(series.get_by_time(time=self.t1, keys="v2"))) self.assertEqual(2.4, series.get_by_time(time=self.t2, keys="v1")) self.assertEqual(3.0, series.get_by_time(time=self.t2, keys="v2")) # time only self.assertEqual({"timestamp": self.t1, "v1": 2, "v2": np.nan}, series.get_by_time(time=self.t1)) self.assertEqual({"timestamp": self.t2, "v1": 2.4, "v2": 3.0}, series.get_by_time(time=self.t2))
def test_override_w_same_time(self): series = DataSeries(keys=set(["timestamp", "v1", "v2", "v3"])) series.add({"timestamp": self.t1, "v1": 2, "v2": 3}) self.assertEqual(1, series.size()) self.assertEqual(2, series.get_by_idx(0, "v1")) self.assertEqual(2, series.get_by_time(self.t1, "v1")) self.assertEqual(3, series.get_by_idx(0, "v2")) self.assertEqual(3, series.get_by_time(self.t1, "v2")) self.assertTrue(np.isnan(series.get_by_idx(0, "v3"))) self.assertTrue(np.isnan(series.get_by_time(self.t1, "v3"))) series.add({"timestamp": self.t1, "v1": 2.4, "v2": 3.4, "v3": 1.1}) self.assertEqual(1, series.size()) self.assertEqual(2.4, series.get_by_idx(0, "v1")) self.assertEqual(2.4, series.get_by_time(self.t1, "v1")) self.assertEqual(3.4, series.get_by_idx(0, "v2")) self.assertEqual(3.4, series.get_by_time(self.t1, "v2")) self.assertEqual(1.1, series.get_by_idx(0, "v3")) self.assertEqual(1.1, series.get_by_time(self.t1, "v3")) series.add({"timestamp": self.t2, "v1": 2.6, "v2": 3.6}) self.assertEqual(2, series.size()) self.assertEqual(2.4, series.get_by_idx(0, "v1")) self.assertEqual(2.4, series.get_by_time(self.t1, "v1")) self.assertEqual(3.4, series.get_by_idx(0, "v2")) self.assertEqual(3.4, series.get_by_time(self.t1, "v2")) self.assertEqual(1.1, series.get_by_idx(0, "v3")) self.assertEqual(1.1, series.get_by_time(self.t1, "v3")) self.assertEqual(2.6, series.get_by_idx(1, "v1")) self.assertEqual(2.6, series.get_by_time(self.t2, "v1")) self.assertEqual(3.6, series.get_by_idx(1, "v2")) self.assertEqual(3.6, series.get_by_time(self.t2, "v2")) self.assertTrue(np.isnan(series.get_by_idx(1, "v3"))) self.assertTrue(np.isnan(series.get_by_time(self.t2, "v3")))
class Portfolio(PositionHolder, OrderEventHandler, ExecutionEventHandler, MarketDataEventHandler, AccountEventHandler, Persistable, Startable, HasId): __slots__ = ( 'portf_id', 'ord_reqs', 'orders', 'app_context', 'performance_series', 'total_equity', 'cash', 'stock_value', 'analyzers', ) __transient__ = ( 'ord_reqs', 'orders', 'app_context', ) def __init__(self, portf_id="test", cash=1000000, analyzers=None): super(Portfolio, self).__init__() self.portf_id = portf_id self.ord_reqs = {} self.orders = {} self.performance_series = DataSeries("%s.Performance" % self.portf_id, missing_value=0) self.total_equity = 0 self.cash = cash self.stock_value = 0 self.analyzers = analyzers if analyzers is not None else [Pnl(), DrawDown()] def _start(self, app_context, **kwargs): self.app_context.portf_mgr.add(self) for analyzer in self.analyzers: analyzer.set_portfolio(self) for order in self.app_context.order_mgr.get_portf_orders(self.id()): self._add_order(order) for order_req in self.app_context.order_mgr.get_strategy_order_reqs(self.id()): self._add_order_req(order_req) self.__event_subscription = EventBus.data_subject.subscribe(self.on_next) def _stop(self): self.__event_subscription.dispose() def id(self): return self.portf_id def all_orders(self): return [order for cl_orders in self.orders.values() for order in cl_orders.values()] def get_order(self, cl_id, cl_ord_id): if cl_id not in self.orders: return None return self.orders[cl_id].get(cl_ord_id, None) def on_bar(self, bar): super(Portfolio, self).on_bar(bar) self.__update_equity(bar.timestamp, bar.inst_id, bar.close) def on_quote(self, quote): super(Portfolio, self).on_quote(quote) self.__update_equity(quote.timestamp, quote.inst_id, quote.mid()) def on_trade(self, trade): super(Portfolio, self).on_trade(trade) self.__update_equity(trade.timestamp, trade.inst_id, trade.price) def _add_order(self, order): if order.cl_id not in self.orders: self.orders[order.cl_id] = {} self.orders[order.cl_id][order.cl_ord_id] = order def _add_order_req(self, order_req): if order_req.cl_id not in self.ord_reqs: self.ord_reqs[order_req.cl_id] = {} self.ord_reqs[order_req.cl_id][order_req.cl_ord_id] = order_req def send_order(self, new_ord_req): logger.debug("[%s] %s" % (self.__class__.__name__, new_ord_req)) if new_ord_req.cl_id in self.ord_reqs and new_ord_req.cl_ord_id in self.ord_reqs[new_ord_req.cl_id]: raise RuntimeError("ord_reqs[%s][%s] already exist" % (new_ord_req.cl_id, new_ord_req.cl_ord_id)) self._add_order_req(new_ord_req) order = self.app_context.order_mgr.send_order(new_ord_req) self._add_order(order) self.get_position(order.inst_id).add_order(order) return order def cancel_order(self, ord_cancel_req): logger.debug("[%s] %s" % (self.__class__.__name__, ord_cancel_req)) order = self.app_context.order_mgr.cancel_order(ord_cancel_req) return order def replace_order(self, ord_replace_req): logger.debug("[%s] %s" % (self.__class__.__name__, ord_replace_req)) order = self.app_context.order_mgr.replace_order(ord_replace_req) return order def on_new_ord_req(self, new_ord_req): if new_ord_req.portf_id == self.portf_id: self.send_order(new_ord_req) def on_ord_cancel_req(self, ord_cancel_req): if ord_cancel_req.portf_id == self.portf_id: self.cancel_order(ord_cancel_req) def on_ord_replace_req(self, ord_replace_req): if ord_replace_req.portf_id == self.portf_id: self.replace_order(ord_replace_req) def on_ord_upd(self, ord_upd): if ord_upd.portf_id == self.portf_id: logger.debug("[%s] %s" % (self.__class__.__name__, ord_upd)) def on_exec_report(self, exec_report): logger.debug("[%s] %s" % (self.__class__.__name__, exec_report)) if exec_report.cl_id not in self.ord_reqs and exec_report.cl_ord_id not in self.ord_reqs[exec_report.cl_id]: raise Exception("Order not found, ord_reqs[%s][%s]" % (exec_report.cl_id, exec_report.cl_ord_id)) new_ord_req = self.ord_reqs[exec_report.cl_id][exec_report.cl_ord_id] direction = 1 if new_ord_req.action == OrdAction.BUY else -1 if exec_report.last_qty > 0: inst = self.app_context.ref_data_mgr.get_inst(exec_report.inst_id) multiplier = inst.factor if inst.type in [InstType.Future, InstType.Option] else 1 self.cash -= (direction * multiplier* exec_report.last_qty * exec_report.last_price + exec_report.commission) self.add_position(exec_report.inst_id, exec_report.cl_id, exec_report.cl_ord_id, direction * exec_report.last_qty) self.update_position_price(exec_report.timestamp, exec_report.inst_id, multiplier*exec_report.last_price) def update_position_price(self, timestamp, inst_id, price): super(Portfolio, self).update_position_price(timestamp, inst_id, price) self.__update_equity(timestamp, inst_id, price) for analyzer in self.analyzers: analyzer.update(timestamp) def __update_equity(self, time, inst_id, price): self.stock_value = 0 for position in self.positions.itervalues(): self.stock_value += position.current_value() self.total_equity = self.stock_value + self.cash self.performance_series.add( {"timestamp": time, "stock_value": self.stock_value, "cash": self.cash, "total_equity": self.total_equity}) def get_return(self): equity = self.performance_series.get_series("total_equity") equity.name = 'equity' rets = equity.pct_change().dropna() # rets.index = rets.index.tz_localize("UTC") return rets def get_series(self): result = self.performance_series.get_series(['stock_value', 'cash', 'total_equity']) for analyzer in self.analyzers: result.update(analyzer.get_series()) return result def get_result(self): result = { "TotalEquity": self.total_equity, "Cash": self.cash, "StockValue": self.stock_value } for analyzer in self.analyzers: result.update(analyzer.get_result()) return result def on_acc_upd(self, acc_upd): pass def on_portf_upd(self, portf_upd): # TODO pass
class BarAggregatorTest(TestCase): class DummyEventBus: def __init__(self): self.items = [] def reset(self): self.items = [] def on_next(self, item): print item self.items.append(item) def setUp(self): self.time = 9000000000 self.simluation_clock = SimulationClock() self.simluation_clock.reset() self.simluation_clock.update_time(self.time) self.input = DataSeries() self.event_bus = BarAggregatorTest.DummyEventBus() def update(self, input, data): self.simluation_clock.update_time(data.timestamp) self.input.add(data.to_dict()) def test_time_bar_from_trade(self): agg = BarAggregator(data_bus=self.event_bus, clock=self.simluation_clock, inst_id=1, input=self.input) agg.start() self.assertEqual(0, len(self.event_bus.items)) self.time += 10000 t = Trade(timestamp=self.time, inst_id=1, price=20, size=200) self.update(self.input, t) self.assertEqual(1, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) # expect get a aggregated bar at 9000059999 self.time += 49999 t = Trade(timestamp=self.time, inst_id=1, price=10, size=200) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(0, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000000000, timestamp=9000059999, type=1, size=60, open=20, high=20, low=10, close=10, vol=400, adj_close=0), items[0]) def test_time_bar_from_bid(self): agg = BarAggregator(data_bus=self.event_bus, clock=self.simluation_clock, inst_id=1, input=self.input, input_type=BarInputType.Bid) agg.start() self.assertEqual(0, len(self.event_bus.items)) self.time += 10000 t = Quote(timestamp=self.time, inst_id=1, bid=30, bid_size=100) self.update(self.input, t) self.assertEqual(1, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 10000 t = Quote(timestamp=self.time, inst_id=1, bid=10, bid_size=200) self.update(self.input, t) self.assertEqual(2, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 10000 t = Quote(timestamp=self.time, inst_id=1, bid=70, bid_size=300) self.update(self.input, t) self.assertEqual(3, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 29998 t = Quote(timestamp=self.time, inst_id=1, bid=50, bid_size=400) self.update(self.input, t) self.assertEqual(4, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 3 self.simluation_clock.update_time(self.time) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(0, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000000000, timestamp=9000059999, type=1, size=60, open=30, high=70, low=10, close=50, vol=1000, adj_close=0), items[0]) def test_time_bar_from_ask(self): agg = BarAggregator(data_bus=self.event_bus, clock=self.simluation_clock, inst_id=1, input=self.input, input_type=BarInputType.Ask) agg.start() self.assertEqual(0, len(self.event_bus.items)) self.time += 10000 t = Quote(timestamp=self.time, inst_id=1, ask=30, ask_size=100) self.update(self.input, t) self.assertEqual(1, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 60000 t = Quote(timestamp=self.time, inst_id=1, ask=70, ask_size=300) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(1, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000000000, timestamp=9000059999, type=1, size=60, open=30, high=30, low=30, close=30, vol=100, adj_close=0), items[0]) self.event_bus.reset() self.time += 49999 t = Quote(timestamp=self.time, inst_id=1, ask=20, ask_size=100) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(0, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000060000, timestamp=9000119999, type=1, size=60, open=70, high=70, low=20, close=20, vol=400, adj_close=0), items[0]) def test_time_bar_from_bidask(self): agg = BarAggregator(data_bus=self.event_bus, clock=self.simluation_clock, inst_id=1, input=self.input, input_type=BarInputType.BidAsk) agg.start() self.assertEqual(0, len(self.event_bus.items)) self.time += 10000 t = Quote(timestamp=self.time, inst_id=1, ask=30, ask_size=100, bid=0, bid_size=200) self.update(self.input, t) self.assertEqual(1, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 10000 t = Quote(timestamp=self.time, inst_id=1, ask=20, ask_size=150, bid=10, bid_size=0) self.update(self.input, t) self.assertEqual(2, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 39999 t = Quote(timestamp=self.time, inst_id=1, ask=70, ask_size=300, bid=80, bid_size=10) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(0, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000000000, timestamp=9000059999, type=1, size=60, open=30, high=80, low=20, close=80, vol=260, adj_close=0), items[0]) def test_time_bar_from_mid(self): agg = BarAggregator(data_bus=self.event_bus, clock=self.simluation_clock, inst_id=1, input=self.input, input_type=BarInputType.Middle) agg.start() self.assertEqual(0, len(self.event_bus.items)) self.time += 59999 t = Quote(timestamp=self.time, inst_id=1, ask=30, ask_size=100, bid=18, bid_size=200) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(0, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000000000, timestamp=9000059999, type=1, size=60, open=24, high=24, low=24, close=24, vol=150, adj_close=0), items[0]) def test_tick_bar_from_trade(self): agg = BarAggregator(data_bus=self.event_bus, clock=self.simluation_clock, inst_id=1, input=self.input, output_bar_type=BarType.Tick, output_size=3) agg.start() self.assertEqual(0, len(self.event_bus.items)) self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=20, size=200) self.update(self.input, t) self.assertEqual(1, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=80, size=100) self.update(self.input, t) self.assertEqual(2, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=10, size=200) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(0, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000060000, timestamp=9000180000, type=BarType.Tick, size=3, open=20, high=80, low=10, close=10, vol=500, adj_close=0), items[0]) def test_vol_bar_from_trade(self): agg = BarAggregator(data_bus=self.event_bus, clock=self.simluation_clock, inst_id=1, input=self.input, output_bar_type=BarType.Volume, output_size=1000) agg.start() self.assertEqual(0, len(self.event_bus.items)) self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=20, size=200) self.update(self.input, t) self.assertEqual(1, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=80, size=100) self.update(self.input, t) self.assertEqual(2, agg.count()) self.assertTrue(len(self.event_bus.items) == 0) self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=10, size=1000) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(1, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000060000, timestamp=9000180000, type=BarType.Volume, size=1000, open=20, high=80, low=10, close=10, vol=1000, adj_close=0), items[0]) self.event_bus.reset() self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=50, size=2800) self.update(self.input, t) items = self.event_bus.items self.assertEqual(3, len(items)) self.assertEqual(1, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000180000, timestamp=9000240000, type=BarType.Volume, size=1000, open=10, high=50, low=10, close=50, vol=1000, adj_close=0), items[0]) self.assertEqual( Bar(inst_id=1, begin_time=9000240000, timestamp=9000240000, type=BarType.Volume, size=1000, open=50, high=50, low=50, close=50, vol=1000, adj_close=0), items[1]) self.assertEqual( Bar(inst_id=1, begin_time=9000240000, timestamp=9000240000, type=BarType.Volume, size=1000, open=50, high=50, low=50, close=50, vol=1000, adj_close=0), items[2]) self.event_bus.reset() self.time += 60000 t = Trade(timestamp=self.time, inst_id=1, price=20, size=900) self.update(self.input, t) items = self.event_bus.items self.assertEqual(1, len(items)) self.assertEqual(0, agg.count()) self.assertEqual( Bar(inst_id=1, begin_time=9000240000, timestamp=9000300000, type=BarType.Volume, size=1000, open=50, high=50, low=20, close=20, vol=1000, adj_close=0), items[0])
rsi_value = 100 - 100 / (1 + rs) self.__prev_gain = avg_gain self.__prev_loss = avg_loss result[Indicator.VALUE] = rsi_value else: result[Indicator.VALUE] = np.nan self.add(result) if __name__ == "__main__": import datetime from algotrader.utils.time_series import DataSeries close = DataSeries("close") rsi = RSI(close, input_key='close', length=14) print rsi.name t = datetime.datetime.now() values = [ 44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42, 45.84, 46.08, 45.89, 46.03, 45.61, 46.28, 46.28, 46.00 ] for idx, value in enumerate(values): close.add({'timestamp': t, 'close': value}) t = t + datetime.timedelta(0, 3) print idx, rsi.now()