diff --git a/example_data/generated_config.json b/example_data/generated_config.json index e1cfa3e..ca78b94 100644 --- a/example_data/generated_config.json +++ b/example_data/generated_config.json @@ -2,7 +2,7 @@ "title": "SMA_6H_week", "description": "mass simulation test 0514-23, 0614-21, 0719-26, 0804-11", "budget": 5000000, - "strategy": "1", + "strategy": "SMA", "interval": 1e-06, "currency": "BTC", "period_list": [ diff --git a/example_data/generated_config_mix.json b/example_data/generated_config_mix.json index c4a6c6e..a86cebc 100644 --- a/example_data/generated_config_mix.json +++ b/example_data/generated_config_mix.json @@ -2,7 +2,7 @@ "title": "SMA_6H_week_mix", "description": "mass simulation test 0514-23, 0614-21, 0719-26, 0804-11", "budget": 5000000, - "strategy": "1", + "strategy": "SMA", "interval": 1e-06, "currency": "BTC", "period_list": [ diff --git a/example_data/sma0_simulation.json b/example_data/sma0_simulation.json index b1fb2b2..19a406a 100644 --- a/example_data/sma0_simulation.json +++ b/example_data/sma0_simulation.json @@ -2,7 +2,7 @@ "title": "BnH-2Hour", "description": "BnH 2시간 간격으로 일주일 진행", "budget": 50000, - "strategy": 0, + "strategy": "BNH", "interval": 0.1, "currency": "BTC", "period_list": [ diff --git a/integration_tests/analyzer_ITG_test.py b/integration_tests/analyzer_ITG_test.py index 02d1b35..8258743 100644 --- a/integration_tests/analyzer_ITG_test.py +++ b/integration_tests/analyzer_ITG_test.py @@ -24,16 +24,19 @@ def test_update_info_func(): analyzer.make_start_point() # 1턴 정보 업데이트 - info = { - "market": "KRW-BTC", - "date_time": "2020-12-21T01:13:00", - "opening_price": 26155000.0, - "high_price": 26158000.0, - "low_price": 26132000.0, - "closing_price": 26145000.0, - "acc_price": 116448937.40051, - "acc_volume": 4.45311465, - } + info = [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-12-21T01:13:00", + "opening_price": 26155000.0, + "high_price": 26158000.0, + "low_price": 26132000.0, + "closing_price": 26145000.0, + "acc_price": 116448937.40051, + "acc_volume": 4.45311465, + } + ] analyzer.put_trading_info(info) analyzer.add_value_for_line_graph("2020-12-21T01:13:00", 26132000.0) analyzer.add_value_for_line_graph("2020-12-21T01:13:01", 26158000.0) @@ -76,16 +79,19 @@ def test_update_info_func(): analyzer.update_asset_info() # 2턴 정보 업데이트 - info = { - "market": "KRW-BTC", - "date_time": "2020-12-21T01:14:00", - "opening_price": 26145000.0, - "high_price": 26153000.0, - "low_price": 26132000.0, - "closing_price": 26132000.0, - "acc_price": 57246220.95838, - "acc_volume": 2.18982408, - } + info = [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-12-21T01:14:00", + "opening_price": 26145000.0, + "high_price": 26153000.0, + "low_price": 26132000.0, + "closing_price": 26132000.0, + "acc_price": 57246220.95838, + "acc_volume": 2.18982408, + } + ] analyzer.put_trading_info(info) analyzer.add_drawing_spot("2020-12-21T01:14:00", 26020000.0) @@ -132,16 +138,19 @@ def test_update_info_func(): analyzer.update_asset_info() # 3턴 정보 업데이트 - info = { - "market": "KRW-BTC", - "date_time": "2020-12-21T01:15:00", - "opening_price": 26148000.0, - "high_price": 26153000.0, - "low_price": 26100000.0, - "closing_price": 26100000.0, - "acc_price": 213292694.20168, - "acc_volume": 8.16909933, - } + info = [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-12-21T01:15:00", + "opening_price": 26148000.0, + "high_price": 26153000.0, + "low_price": 26100000.0, + "closing_price": 26100000.0, + "acc_price": 213292694.20168, + "acc_volume": 8.16909933, + } + ] analyzer.put_trading_info(info) requests = [ @@ -182,16 +191,19 @@ def test_update_info_func(): analyzer.update_asset_info() # 4턴 정보 업데이트 - info = { - "market": "KRW-BTC", - "date_time": "2020-12-21T01:16:00", - "opening_price": 26101000.0, - "high_price": 26114000.0, - "low_price": 26055000.0, - "closing_price": 26083000.0, - "acc_price": 164768010.7268, - "acc_volume": 6.31952174, - } + info = [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-12-21T01:16:00", + "opening_price": 26101000.0, + "high_price": 26114000.0, + "low_price": 26055000.0, + "closing_price": 26083000.0, + "acc_price": 164768010.7268, + "acc_volume": 6.31952174, + } + ] analyzer.put_trading_info(info) requests = [ @@ -232,16 +244,19 @@ def test_update_info_func(): analyzer.update_asset_info() # 5턴 정보 업데이트 - info = { - "market": "KRW-BTC", - "date_time": "2020-12-21T01:17:00", - "opening_price": 26055000.0, - "high_price": 26085000.0, - "low_price": 26055000.0, - "closing_price": 26061000.0, - "acc_price": 42703199.9218, - "acc_volume": 1.63862358, - } + info = [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-12-21T01:17:00", + "opening_price": 26055000.0, + "high_price": 26085000.0, + "low_price": 26055000.0, + "closing_price": 26061000.0, + "acc_price": 42703199.9218, + "acc_volume": 1.63862358, + } + ] analyzer.put_trading_info(info) analyzer.add_drawing_spot("2020-12-21T01:17:00", 25061000.0) diff --git a/integration_tests/binance_data_provider_ITG_test.py b/integration_tests/binance_data_provider_ITG_test.py index 8fec096..329e98d 100644 --- a/integration_tests/binance_data_provider_ITG_test.py +++ b/integration_tests/binance_data_provider_ITG_test.py @@ -12,7 +12,8 @@ def tearDown(self): def test_ITG_get_info_return_correct_data(self): dp = BinanceDataProvider() - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual("market" in info, True) self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -24,7 +25,8 @@ def test_ITG_get_info_return_correct_data(self): def test_ITG_get_info_return_correct_data_when_currency_is_BTC(self): dp = BinanceDataProvider("BTC") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "BTC") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -36,7 +38,8 @@ def test_ITG_get_info_return_correct_data_when_currency_is_BTC(self): def test_ITG_get_info_return_correct_data_when_currency_is_ETH(self): dp = BinanceDataProvider("ETH") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "ETH") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -48,7 +51,8 @@ def test_ITG_get_info_return_correct_data_when_currency_is_ETH(self): def test_ITG_get_info_return_correct_data_when_currency_is_DOGE(self): dp = BinanceDataProvider("DOGE") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "DOGE") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -60,7 +64,8 @@ def test_ITG_get_info_return_correct_data_when_currency_is_DOGE(self): def test_ITG_get_info_return_correct_data_when_currency_is_XRP(self): dp = BinanceDataProvider("XRP") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "XRP") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) diff --git a/integration_tests/bithumb_data_provider_ITG_test.py b/integration_tests/bithumb_data_provider_ITG_test.py index 70a0ad5..d179c3e 100644 --- a/integration_tests/bithumb_data_provider_ITG_test.py +++ b/integration_tests/bithumb_data_provider_ITG_test.py @@ -7,7 +7,8 @@ class BithumbDataProviderIntegrationTests(unittest.TestCase): def test_ITG_get_info_return_correct_data(self): dp = BithumbDataProvider() - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual("market" in info, True) self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) diff --git a/integration_tests/operator_ITG_test.py b/integration_tests/operator_ITG_test.py index 72df232..dd2d2dc 100644 --- a/integration_tests/operator_ITG_test.py +++ b/integration_tests/operator_ITG_test.py @@ -18,7 +18,9 @@ def check_interval(): count += 1 now = time.time() interval = now - last_time - print(f"count {count}, interval {interval}, now {now}, last_time {last_time}") + print( + f"count {count}, interval {interval}, now {now}, last_time {last_time}" + ) if count > 1 and count < 4: self.assertTrue(interval > 0.9) self.assertTrue(interval < 1.1) @@ -31,7 +33,9 @@ def check_interval(): op.initialize(data_provider, strategy, trader, analyzer, budget=50000) self.assertEqual(op.state, "ready") analyzer.initialize.assert_called_with(trader.get_account_info) - strategy.initialize.assert_called_with(50000, add_spot_callback=ANY, add_line_callback=ANY) + strategy.initialize.assert_called_with( + 50000, add_spot_callback=ANY, add_line_callback=ANY + ) strategy.get_request.return_value = "mango" op.set_interval(1) diff --git a/integration_tests/strategy_bnh/bnh_ITG_test.py b/integration_tests/strategy_bnh/bnh_ITG_test.py index f803cd4..8962f89 100644 --- a/integration_tests/strategy_bnh/bnh_ITG_test.py +++ b/integration_tests/strategy_bnh/bnh_ITG_test.py @@ -62,9 +62,17 @@ def test_ITG_run_single_simulation(self): for result_idx, request_list in enumerate(result_list): for request_idx, requst in enumerate(request_list): target = expected[result_idx][request_idx] - self.assertEqual(requst["type"], target["type"], f"{result_idx}-{request_idx}") - self.assertEqual(requst["price"], target["price"], f"{result_idx}-{request_idx}") - self.assertEqual(requst["amount"], target["amount"], f"{result_idx}-{request_idx}") self.assertEqual( - requst["date_time"], target["date_time"], f"{result_idx}-{request_idx}" + requst["type"], target["type"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["price"], target["price"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["amount"], target["amount"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["date_time"], + target["date_time"], + f"{result_idx}-{request_idx}", ) diff --git a/integration_tests/strategy_bnh_ITG_test.py b/integration_tests/strategy_bnh_ITG_test.py index 7544959..2653730 100644 --- a/integration_tests/strategy_bnh_ITG_test.py +++ b/integration_tests/strategy_bnh_ITG_test.py @@ -10,16 +10,19 @@ def test_ITG_strategy_buy_and_hold_full(self): strategy.initialize(50000, 5000) # 거래 정보 입력 - 1 strategy.update_trading_info( - { - "market": "KRW-BTC", - "date_time": "2020-04-30T14:51:00", - "opening_price": 11288000.0, - "high_price": 11304000.0, - "low_price": 11282000.0, - "closing_price": 11304000.0, - "acc_price": 587101574.8949, - "acc_volume": 51.97606868, - } + [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-04-30T14:51:00", + "opening_price": 11288000.0, + "high_price": 11304000.0, + "low_price": 11282000.0, + "closing_price": 11304000.0, + "acc_price": 587101574.8949, + "acc_volume": 51.97606868, + } + ] ) # 거래 요청 정보 생성 request = strategy.get_request() @@ -54,16 +57,19 @@ def test_ITG_strategy_buy_and_hold_full(self): # 거래 정보 입력 - 2 strategy.update_trading_info( - { - "market": "KRW-BTC", - "date_time": "2020-04-30T14:52:00", - "opening_price": 11304000.0, - "high_price": 21304000.0, - "low_price": 11304000.0, - "closing_price": 21304000.0, - "acc_price": 587101574.8949, - "acc_volume": 51.97606868, - } + [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-04-30T14:52:00", + "opening_price": 11304000.0, + "high_price": 21304000.0, + "low_price": 11304000.0, + "closing_price": 21304000.0, + "acc_price": 587101574.8949, + "acc_volume": 51.97606868, + } + ] ) # 거래 요청 정보 생성 request = strategy.get_request() @@ -100,16 +106,19 @@ def test_ITG_strategy_buy_and_hold_full(self): # 거래 정보 입력 - 3 strategy.update_trading_info( - { - "market": "KRW-BTC", - "date_time": "2020-04-30T14:52:00", - "opening_price": 21304000.0, - "high_price": 21304000.0, - "low_price": 21304000.0, - "closing_price": 21304000.0, - "acc_price": 587101574.8949, - "acc_volume": 51.97606868, - } + [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-04-30T14:52:00", + "opening_price": 21304000.0, + "high_price": 21304000.0, + "low_price": 21304000.0, + "closing_price": 21304000.0, + "acc_price": 587101574.8949, + "acc_volume": 51.97606868, + } + ] ) # 거래 요청 정보 생성 request = strategy.get_request() @@ -147,16 +156,19 @@ def test_ITG_strategy_buy_and_hold_full(self): # 거래 정보 입력 - 4 strategy.update_trading_info( - { - "market": "KRW-BTC", - "date_time": "2020-04-30T14:52:00", - "opening_price": 21304000.0, - "high_price": 41304000.0, - "low_price": 21304000.0, - "closing_price": 41304000.0, - "acc_price": 587101574.8949, - "acc_volume": 51.97606868, - } + [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-04-30T14:52:00", + "opening_price": 21304000.0, + "high_price": 41304000.0, + "low_price": 21304000.0, + "closing_price": 41304000.0, + "acc_price": 587101574.8949, + "acc_volume": 51.97606868, + } + ] ) # 거래 요청 정보 생성 request = strategy.get_request() @@ -192,16 +204,19 @@ def test_ITG_strategy_buy_and_hold_full(self): # 거래 정보 입력 - 5 strategy.update_trading_info( - { - "market": "KRW-BTC", - "date_time": "2020-04-30T14:52:00", - "opening_price": 41304000.0, - "high_price": 61304000.0, - "low_price": 41304000.0, - "closing_price": 61304000.0, - "acc_price": 587101574.8949, - "acc_volume": 51.97606868, - } + [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-04-30T14:52:00", + "opening_price": 41304000.0, + "high_price": 61304000.0, + "low_price": 41304000.0, + "closing_price": 61304000.0, + "acc_price": 587101574.8949, + "acc_volume": 51.97606868, + } + ] ) # 거래 요청 정보 생성 request = strategy.get_request() @@ -237,16 +252,19 @@ def test_ITG_strategy_buy_and_hold_full(self): # 거래 정보 입력 - 6 strategy.update_trading_info( - { - "market": "KRW-BTC", - "date_time": "2020-04-30T14:52:00", - "opening_price": 61304000.0, - "high_price": 61304000.0, - "low_price": 61304000.0, - "closing_price": 61304000.0, - "acc_price": 587101574.8949, - "acc_volume": 51.97606868, - } + [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-04-30T14:52:00", + "opening_price": 61304000.0, + "high_price": 61304000.0, + "low_price": 61304000.0, + "closing_price": 61304000.0, + "acc_price": 587101574.8949, + "acc_volume": 51.97606868, + } + ] ) # 거래 요청 정보 생성 request = strategy.get_request() @@ -282,16 +300,19 @@ def test_ITG_strategy_buy_and_hold_full(self): # 거래 정보 입력 - 7 strategy.update_trading_info( - { - "market": "KRW-BTC", - "date_time": "2020-04-30T14:52:00", - "opening_price": 61304000.0, - "high_price": 61304000.0, - "low_price": 61304000.0, - "closing_price": 61304000.0, - "acc_price": 587101574.8949, - "acc_volume": 51.97606868, - } + [ + { + "type": "primary_candle", + "market": "KRW-BTC", + "date_time": "2020-04-30T14:52:00", + "opening_price": 61304000.0, + "high_price": 61304000.0, + "low_price": 61304000.0, + "closing_price": 61304000.0, + "acc_price": 587101574.8949, + "acc_volume": 51.97606868, + } + ] ) # 거래 요청 정보 생성 request = strategy.get_request() diff --git a/integration_tests/strategy_sma/sma_ITG_test.py b/integration_tests/strategy_sma/sma_ITG_test.py index d01454b..a2274b3 100644 --- a/integration_tests/strategy_sma/sma_ITG_test.py +++ b/integration_tests/strategy_sma/sma_ITG_test.py @@ -62,9 +62,17 @@ def test_ITG_run_single_simulation(self): for result_idx, request_list in enumerate(result_list): for request_idx, requst in enumerate(request_list): target = expected[result_idx][request_idx] - self.assertEqual(requst["type"], target["type"], f"{result_idx}-{request_idx}") - self.assertEqual(requst["price"], target["price"], f"{result_idx}-{request_idx}") - self.assertEqual(requst["amount"], target["amount"], f"{result_idx}-{request_idx}") self.assertEqual( - requst["date_time"], target["date_time"], f"{result_idx}-{request_idx}" + requst["type"], target["type"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["price"], target["price"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["amount"], target["amount"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["date_time"], + target["date_time"], + f"{result_idx}-{request_idx}", ) diff --git a/integration_tests/strategy_sml/sml_ITG_test.py b/integration_tests/strategy_sml/sml_ITG_test.py index 836a2ad..7571657 100644 --- a/integration_tests/strategy_sml/sml_ITG_test.py +++ b/integration_tests/strategy_sml/sml_ITG_test.py @@ -62,9 +62,17 @@ def test_ITG_run_single_simulation(self): for result_idx, request_list in enumerate(result_list): for request_idx, requst in enumerate(request_list): target = expected[result_idx][request_idx] - self.assertEqual(requst["type"], target["type"], f"{result_idx}-{request_idx}") - self.assertEqual(requst["price"], target["price"], f"{result_idx}-{request_idx}") - self.assertEqual(requst["amount"], target["amount"], f"{result_idx}-{request_idx}") self.assertEqual( - requst["date_time"], target["date_time"], f"{result_idx}-{request_idx}" + requst["type"], target["type"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["price"], target["price"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["amount"], target["amount"], f"{result_idx}-{request_idx}" + ) + self.assertEqual( + requst["date_time"], + target["date_time"], + f"{result_idx}-{request_idx}", ) diff --git a/integration_tests/upbit_data_provider_ITG_test.py b/integration_tests/upbit_data_provider_ITG_test.py index 6ff7d0a..2f9e99a 100644 --- a/integration_tests/upbit_data_provider_ITG_test.py +++ b/integration_tests/upbit_data_provider_ITG_test.py @@ -7,7 +7,8 @@ class UpbitDataProviderIntegrationTests(unittest.TestCase): def test_ITG_get_info_return_correct_data(self): dp = UpbitDataProvider() - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual("market" in info, True) self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -21,7 +22,8 @@ def test_ITG_get_info_return_correct_data(self): def test_ITG_get_info_return_correct_data_when_currency_is_BTC(self): dp = UpbitDataProvider("BTC") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "BTC") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -35,7 +37,8 @@ def test_ITG_get_info_return_correct_data_when_currency_is_BTC(self): def test_ITG_get_info_return_correct_data_when_currency_is_ETH(self): dp = UpbitDataProvider("ETH") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "ETH") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -49,7 +52,8 @@ def test_ITG_get_info_return_correct_data_when_currency_is_ETH(self): def test_ITG_get_info_return_correct_data_when_currency_is_DOGE(self): dp = UpbitDataProvider("DOGE") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "DOGE") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) @@ -63,7 +67,8 @@ def test_ITG_get_info_return_correct_data_when_currency_is_DOGE(self): def test_ITG_get_info_return_correct_data_when_currency_is_XRP(self): dp = UpbitDataProvider("XRP") - info = dp.get_info() + info = dp.get_info()[0] + self.assertEqual(info["type"], "primary_candle") self.assertEqual(info["market"], "XRP") self.assertEqual("date_time" in info, True) self.assertEqual("opening_price" in info, True) diff --git a/smtm/analyzer.py b/smtm/analyzer.py index 8b9ca2b..c67e8a7 100644 --- a/smtm/analyzer.py +++ b/smtm/analyzer.py @@ -83,7 +83,16 @@ def put_trading_info(self, info): 2: 매매 결과 3: 수익률 정보 """ - new = copy.deepcopy(info) + target = None + for item in info: + if item["type"] == "primary_candle": + target = item + break + + if target is None: + return + + new = copy.deepcopy(target) new["kind"] = 0 self.info_list.append(new) self.make_periodic_record() diff --git a/smtm/data/binance_data_provider.py b/smtm/data/binance_data_provider.py index aaa192f..4809073 100644 --- a/smtm/data/binance_data_provider.py +++ b/smtm/data/binance_data_provider.py @@ -57,7 +57,7 @@ def get_info(self): } """ data = self._get_data_from_server() - return self._create_candle_info(data[0]) + return [self._create_candle_info(data[0])] def _create_candle_info(self, data): """ @@ -81,6 +81,7 @@ def _create_candle_info(self, data): """ try: return { + "type": "primary_candle", "market": self.market, "date_time": self._get_kst_time_from_unix_time_ms(data[0]), "opening_price": float(data[1]), diff --git a/smtm/data/bithumb_data_provider.py b/smtm/data/bithumb_data_provider.py index 4769692..8000594 100644 --- a/smtm/data/bithumb_data_provider.py +++ b/smtm/data/bithumb_data_provider.py @@ -47,11 +47,12 @@ def get_info(self): if data["status"] != "0000": raise UserWarning("Fail get data from sever") - return self.__create_candle_info(data["data"][-1]) + return [self.__create_candle_info(data["data"][-1])] def __create_candle_info(self, data): try: return { + "type": "primary_candle", "market": self.market, "date_time": datetime.fromtimestamp( data[0] / 1000.0, tz=self.KST diff --git a/smtm/data/data_provider.py b/smtm/data/data_provider.py index 704f1e5..a68c37e 100644 --- a/smtm/data/data_provider.py +++ b/smtm/data/data_provider.py @@ -11,17 +11,38 @@ class DataProvider(metaclass=ABCMeta): @abstractmethod def get_info(self): """ - 현재 거래 정보를 딕셔너리로 전달 + 거래 정보나 환율, 지수등의 다양한 정보 딕셔너리들을 리스트로 전달 + 'primary_candle' 타입으로 거래 정보를 전달. + 이외 정보 딕셔너리의 키 값은 type에 따라 다름. Returns: 거래 정보 딕셔너리 - { - "market": 거래 시장 종류 BTC - "date_time": 정보의 기준 시간 - "opening_price": 시작 거래 가격 - "high_price": 최고 거래 가격 - "low_price": 최저 거래 가격 - "closing_price": 마지막 거래 가격 - "acc_price": 단위 시간내 누적 거래 금액 - "acc_volume": 단위 시간내 누적 거래 양 - } + [ + { + "type": 데이터의 종류 e.g. 데이터 출처, 종류에 따른 구분으로 소비자가 데이터를 구분할 수 있게 함 + "market": 거래 시장 종류 BTC + "date_time": 정보의 기준 시간 + "opening_price": 시작 거래 가격 + "high_price": 최고 거래 가격 + "low_price": 최저 거래 가격 + "closing_price": 마지막 거래 가격 + "acc_price": 단위 시간내 누적 거래 금액 + "acc_volume": 단위 시간내 누적 거래 양 + }, + { + "type": 데이터의 종류 e.g. 데이터 출처, 종류에 따른 구분으로 소비자가 데이터를 구분할 수 있게 함 + "usd_krw": 환율 + "date_time": 정보의 기준 시간 + }, + { + "type": 데이터의 종류 e.g. 데이터 출처, 종류에 따른 구분으로 소비자가 데이터를 구분할 수 있게 함 + "market": 거래 시장 종류 BTC + "date_time": 정보의 기준 시간 + "opening_price": 시작 거래 가격 + "high_price": 최고 거래 가격 + "low_price": 최저 거래 가격 + "closing_price": 마지막 거래 가격 + "acc_price": 단위 시간내 누적 거래 금액 + "acc_volume": 단위 시간내 누적 거래 양 + } + ] """ diff --git a/smtm/data/simulation_data_provider.py b/smtm/data/simulation_data_provider.py index ae6fa80..6c851d8 100644 --- a/smtm/data/simulation_data_provider.py +++ b/smtm/data/simulation_data_provider.py @@ -59,4 +59,5 @@ def get_info(self): self.index = now + 1 self.logger.info(f'[DATA] @ {self.data[now]["date_time"]}') - return self.data[now] + self.data[now]["type"] = "primary_candle" + return [self.data[now]] diff --git a/smtm/data/upbit_data_provider.py b/smtm/data/upbit_data_provider.py index bd377ff..aa31c75 100644 --- a/smtm/data/upbit_data_provider.py +++ b/smtm/data/upbit_data_provider.py @@ -51,11 +51,12 @@ def get_info(self): } """ data = self.__get_data_from_server() - return self.__create_candle_info(data[0]) + return [self.__create_candle_info(data[0])] def __create_candle_info(self, data): try: return { + "type": "primary_candle", "market": self.market, "date_time": data["candle_date_time_kst"], "opening_price": float(data["opening_price"]), diff --git a/smtm/strategy/strategy.py b/smtm/strategy/strategy.py index 334452a..f127962 100644 --- a/smtm/strategy/strategy.py +++ b/smtm/strategy/strategy.py @@ -36,19 +36,22 @@ def get_request(self): @abstractmethod def update_trading_info(self, info): - """새로운 거래 정보를 업데이트 + """Data Provider에서 제공받은 새로운 거래 정보를 업데이트 info: - { - "market": 거래 시장 종류 BTC - "date_time": 정보의 기준 시간 - "opening_price": 시작 거래 가격 - "high_price": 최고 거래 가격 - "low_price": 최저 거래 가격 - "closing_price": 마지막 거래 가격 - "acc_price": 단위 시간내 누적 거래 금액 - "acc_volume": 단위 시간내 누적 거래 양 - } + [ + { + "type": 데이터 종류, 소스에 따라 다름, 기본 데이터는 'primary_candle' + "market": 거래 시장 종류 BTC + "date_time": 정보의 기준 시간 + "opening_price": 시작 거래 가격 + "high_price": 최고 거래 가격 + "low_price": 최저 거래 가격 + "closing_price": 마지막 거래 가격 + "acc_price": 단위 시간내 누적 거래 금액 + "acc_volume": 단위 시간내 누적 거래 양 + } + ] """ @abstractmethod diff --git a/smtm/strategy/strategy_bnh.py b/smtm/strategy/strategy_bnh.py index 3b1e8dd..b32de53 100644 --- a/smtm/strategy/strategy_bnh.py +++ b/smtm/strategy/strategy_bnh.py @@ -55,7 +55,17 @@ def update_trading_info(self, info): """ if self.is_intialized is not True: return - self.data.append(copy.deepcopy(info)) + + target = None + for item in info: + if item["type"] == "primary_candle": + target = item + break + + if target is None: + return + + self.data.append(copy.deepcopy(target)) def update_result(self, result): """요청한 거래의 결과를 업데이트 diff --git a/smtm/strategy/strategy_rsi.py b/smtm/strategy/strategy_rsi.py index 8d475a5..ceb284d 100644 --- a/smtm/strategy/strategy_rsi.py +++ b/smtm/strategy/strategy_rsi.py @@ -153,8 +153,18 @@ def update_trading_info(self, info): """ if self.is_intialized is not True or info is None: return - self.data.append(copy.deepcopy(info)) - self._update_rsi(info["closing_price"]) + target = None + for item in info: + if item["type"] == "primary_candle": + target = item + break + + if target is None: + return + + self.data.append(copy.deepcopy(target)) + + self._update_rsi(target["closing_price"]) self._update_position() def _update_position(self): diff --git a/smtm/strategy/strategy_sma_0.py b/smtm/strategy/strategy_sma_0.py index 7d51c92..0b44721 100644 --- a/smtm/strategy/strategy_sma_0.py +++ b/smtm/strategy/strategy_sma_0.py @@ -72,8 +72,17 @@ def update_trading_info(self, info): """ if self.is_intialized is not True: return - self.data.append(copy.deepcopy(info)) - self.__update_process(info) + target = None + for item in info: + if item["type"] == "primary_candle": + target = item + break + + if target is None: + return + + self.data.append(copy.deepcopy(target)) + self.__update_process(target) @staticmethod def _get_deviation_ratio(std, last): diff --git a/smtm/strategy/strategy_sma_ml.py b/smtm/strategy/strategy_sma_ml.py index 23ee2ce..e869772 100644 --- a/smtm/strategy/strategy_sma_ml.py +++ b/smtm/strategy/strategy_sma_ml.py @@ -96,10 +96,19 @@ def update_trading_info(self, info): """ if self.is_intialized is not True: return - self.data.append(copy.deepcopy(info)) - self.__update_process(info) + target = None + for item in info: + if item["type"] == "primary_candle": + target = item + break + + if target is None: + return + + self.data.append(copy.deepcopy(target)) + self.__update_process(target) if self.add_line_callback is not None: - self.add_line_callback(info["date_time"], info["closing_price"]) + self.add_line_callback(target["date_time"], target["closing_price"]) def update_result(self, result): """요청한 거래의 결과를 업데이트 diff --git a/smtm/trader/virtual_market.py b/smtm/trader/virtual_market.py index 119084c..bcbab6c 100644 --- a/smtm/trader/virtual_market.py +++ b/smtm/trader/virtual_market.py @@ -111,7 +111,7 @@ def handle_request(self, request): "state": "done", } - if request["price"] == 0 or request["amount"] == 0: + if float(request["price"]) == 0 or float(request["amount"]) == 0: self.logger.info("turn over") return None @@ -125,7 +125,9 @@ def handle_request(self, request): return result def __handle_buy_request(self, request, next_index, dt): - buy_value = request["price"] * request["amount"] + price = float(request["price"]) + amount = float(request["amount"]) + buy_value = price * amount buy_total_value = buy_value * (1 + self.commission_ratio) old_balance = self.balance @@ -134,19 +136,19 @@ def __handle_buy_request(self, request, next_index, dt): return "pass" try: - if request["price"] < self.data[next_index]["low_price"]: + if price < self.data[next_index]["low_price"]: self.logger.info("not matched") return "pass" name = self.data[next_index]["market"] if name in self.asset: asset = self.asset[name] - new_amount = asset[1] + request["amount"] + new_amount = asset[1] + amount new_amount = round(new_amount, 6) - new_value = (request["amount"] * request["price"]) + (asset[0] * asset[1]) + new_value = (amount * price) + (asset[0] * asset[1]) self.asset[name] = (round(new_value / new_amount), new_amount) else: - self.asset[name] = (request["price"], request["amount"]) + self.asset[name] = (price, amount) self.balance -= buy_total_value self.balance = round(self.balance) @@ -166,6 +168,8 @@ def __handle_buy_request(self, request, next_index, dt): return "error!" def __handle_sell_request(self, request, next_index, dt): + price = float(request["price"]) + amount = float(request["amount"]) old_balance = self.balance try: name = self.data[next_index]["market"] @@ -173,15 +177,15 @@ def __handle_sell_request(self, request, next_index, dt): self.logger.info("asset empty") return "error!" - if request["price"] >= self.data[next_index]["high_price"]: + if price >= self.data[next_index]["high_price"]: self.logger.info("not matched") return "pass" - sell_amount = request["amount"] - if request["amount"] > self.asset[name][1]: + sell_amount = amount + if amount > self.asset[name][1]: sell_amount = self.asset[name][1] self.logger.warning( - f"sell request is bigger than asset {request['amount']} > {sell_amount}" + f"sell request is bigger than asset {amount} > {sell_amount}" ) del self.asset[name] else: @@ -192,8 +196,8 @@ def __handle_sell_request(self, request, next_index, dt): new_amount, ) - sell_value = sell_amount * request["price"] - self.balance += sell_amount * request["price"] * (1 - self.commission_ratio) + sell_value = sell_amount * price + self.balance += sell_amount * price * (1 - self.commission_ratio) self.balance = round(self.balance) self.__print_balance_info("sell", old_balance, self.balance, sell_value) return { diff --git a/tests/analyzer_test.py b/tests/analyzer_test.py index 79bb9eb..a4b8be0 100644 --- a/tests/analyzer_test.py +++ b/tests/analyzer_test.py @@ -16,9 +16,13 @@ def test_add_value_for_line_graph_append_value_info(self): analyzer = Analyzer() analyzer.add_value_for_line_graph("2020-02-27T23:00:00", 12345) analyzer.add_value_for_line_graph("2020-02-27T24:00:00", 700) - self.assertEqual(analyzer.line_graph_list[0]["date_time"], "2020-02-27T23:00:00") + self.assertEqual( + analyzer.line_graph_list[0]["date_time"], "2020-02-27T23:00:00" + ) self.assertEqual(analyzer.line_graph_list[0]["value"], 12345) - self.assertEqual(analyzer.line_graph_list[1]["date_time"], "2020-02-27T24:00:00") + self.assertEqual( + analyzer.line_graph_list[1]["date_time"], "2020-02-27T24:00:00" + ) self.assertEqual(analyzer.line_graph_list[1]["value"], 700) def test_add_drawing_spot_append_spot_info(self): @@ -65,13 +69,20 @@ def test_put_requests_append_request(self): dummy_requests = [ {"id": "papaya", "type": "sell", "price": 5000, "amount": 0.0007}, {"id": "orange", "type": "cancel", "price": 500, "amount": 0.0001}, - {"id": "pear", "type": "buy", "price": 500, "amount": 0.0000000000000000000000001}, + { + "id": "pear", + "type": "buy", + "price": 500, + "amount": 0.0000000000000000000000001, + }, ] analyzer.put_requests(dummy_requests) self.assertEqual(analyzer.request_list[-1]["id"], "pear") self.assertEqual(analyzer.request_list[-1]["type"], "buy") self.assertEqual(analyzer.request_list[-1]["price"], 500.0) - self.assertEqual(analyzer.request_list[-1]["amount"], 0.0000000000000000000000001) + self.assertEqual( + analyzer.request_list[-1]["amount"], 0.0000000000000000000000001 + ) self.assertEqual(analyzer.request_list[-1]["kind"], 1) self.assertEqual(analyzer.request_list[-2]["id"], "orange") @@ -89,9 +100,12 @@ def test_put_requests_append_request(self): def test_put_trading_info_append_trading_info(self): analyzer = Analyzer() analyzer.make_periodic_record = MagicMock() - dummy_info = {"name": "orange"} + dummy_info = [{"type": "primary_candle", "name": "orange"}] analyzer.put_trading_info(dummy_info) - self.assertEqual(analyzer.info_list[-1], {"name": "orange", "kind": 0}) + self.assertEqual( + analyzer.info_list[-1], + {"type": "primary_candle", "name": "orange", "kind": 0}, + ) analyzer.make_periodic_record.assert_called_once() def test_make_periodic_record_should_call_update_asset_info_after_60s_from_last_asset_info( @@ -163,7 +177,9 @@ def test_put_result_append_only_success_result(self): analyzer.put_result(dummy_result) self.assertEqual(analyzer.result_list[-1]["request"]["id"], "kiwi") self.assertEqual(analyzer.result_list[-1]["price"], 500) - self.assertEqual(analyzer.result_list[-1]["amount"], 0.0000000000000000000000001) + self.assertEqual( + analyzer.result_list[-1]["amount"], 0.0000000000000000000000001 + ) self.assertEqual(analyzer.result_list[-1]["kind"], 2) analyzer.update_asset_info.assert_called() @@ -227,13 +243,21 @@ def test_make_start_point_clear_asset_info_and_request_result(self): self.assertEqual(len(analyzer.asset_info_list), 0) analyzer.update_asset_info.assert_called_once() - def test_make_score_record_create_correct_score_record_when_asset_is_not_changed(self): + def test_make_score_record_create_correct_score_record_when_asset_is_not_changed( + self, + ): analyzer = Analyzer() analyzer.make_periodic_record = MagicMock() dummy_asset_info = { "balance": 50000, "asset": {"banana": (1500, 10), "mango": (1000, 4.5), "apple": (250, 2)}, - "quote": {"banana": 1700, "mango": 700, "apple": 500, "pineapple": 300, "kiwi": 77000}, + "quote": { + "banana": 1700, + "mango": 700, + "apple": 500, + "pineapple": 300, + "kiwi": 77000, + }, "date_time": "2020-02-27T23:59:59", } @@ -242,7 +266,9 @@ def test_make_score_record_create_correct_score_record_when_asset_is_not_changed analyzer.asset_info_list.append(dummy_asset_info) analyzer.initialize(MagicMock()) analyzer.is_simulation = True - analyzer.put_trading_info({"date_time": "2020-02-27T23:59:59"}) + analyzer.put_trading_info( + [{"type": "primary_candle", "date_time": "2020-02-27T23:59:59"}] + ) # 유효하지 않은 정보 무시 target_dummy_asset = { "balance": 50000, @@ -253,7 +279,13 @@ def test_make_score_record_create_correct_score_record_when_asset_is_not_changed "pineapple": (0, 2), "kiwi": (77700, 0), }, - "quote": {"banana": 2000, "mango": 1050, "apple": 400, "pineapple": 300, "kiwi": 77000}, + "quote": { + "banana": 2000, + "mango": 1050, + "apple": 400, + "pineapple": 300, + "kiwi": 77000, + }, "date_time": "2020-02-27T23:59:59", } analyzer.make_score_record(target_dummy_asset) @@ -307,7 +339,9 @@ def test_make_score_record_create_correct_score_record_when_asset_is_changed(sel "quote": {"banana": 2000, "mango": 500, "apple": 800}, "date_time": "2020-02-27T23:59:59", } - analyzer.put_trading_info({"date_time": "2020-02-27T23:59:59"}) + analyzer.put_trading_info( + [{"type": "primary_candle", "date_time": "2020-02-27T23:59:59"}] + ) analyzer.make_score_record(target_dummy_asset) self.assertEqual(len(analyzer.score_list), 1) @@ -331,7 +365,9 @@ def test_make_score_record_create_correct_score_record_when_asset_is_changed(sel self.assertEqual(score_record["price_change_ratio"]["apple"], 60) analyzer.make_periodic_record.assert_called_once() - def test_make_score_record_create_correct_score_record_when_start_asset_is_empty(self): + def test_make_score_record_create_correct_score_record_when_start_asset_is_empty( + self, + ): analyzer = Analyzer() analyzer.make_periodic_record = MagicMock() dummy_asset_info = { @@ -351,7 +387,9 @@ def test_make_score_record_create_correct_score_record_when_start_asset_is_empty "quote": {"banana": 2000, "mango": 300, "apple": 750}, "date_time": "2020-02-27T23:59:59", } - analyzer.put_trading_info({"date_time": "2020-02-27T23:59:59"}) + analyzer.put_trading_info( + [{"type": "primary_candle", "date_time": "2020-02-27T23:59:59"}] + ) analyzer.make_score_record(target_dummy_asset) self.assertEqual(len(analyzer.score_list), 1) @@ -397,7 +435,9 @@ def test_make_score_record_create_correct_score_record_when_asset_and_balance_is "date_time": "2020-02-27T23:59:59", } analyzer.make_periodic_record = MagicMock() - analyzer.put_trading_info({"date_time": "2020-02-27T23:59:59"}) + analyzer.put_trading_info( + [{"type": "primary_candle", "date_time": "2020-02-27T23:59:59"}] + ) analyzer.make_score_record(target_dummy_asset) self.assertEqual(len(analyzer.score_list), 1) @@ -476,7 +516,10 @@ def fill_test_data_for_report(self, analyzer): "balance": 5000, "cumulative_return": -65.248, "price_change_ratio": {"mango": -50.0, "apple": 50.0}, - "asset": [("mango", 500, 300, 5.23, -40.0), ("apple", 250, 750, 2.11, 200.0)], + "asset": [ + ("mango", 500, 300, 5.23, -40.0), + ("apple", 250, 750, 2.11, 200.0), + ], "date_time": "2020-02-23T00:00:00", "kind": 3, } @@ -551,7 +594,10 @@ def fill_test_data_for_report(self, analyzer): "balance": 5000, "cumulative_return": -75.067, "price_change_ratio": {"mango": -66.667, "apple": -99.85}, - "asset": [("mango", 600, 200, 4.23, -66.667), ("apple", 500, 0.75, 3.11, -99.85)], + "asset": [ + ("mango", 600, 200, 4.23, -66.667), + ("apple", 500, 0.75, 3.11, -99.85), + ], "date_time": "2020-02-23T00:01:00", "kind": 3, } @@ -617,7 +663,8 @@ def test_get_return_report_return_correct_report(self): self.assertEqual(report[6], -75.067) self.assertEqual(report[7], -65.248) self.assertEqual( - report[8], ("2020-02-23T00:00:00", "2020-02-23T00:00:00", "2020-02-23T00:02:00") + report[8], + ("2020-02-23T00:00:00", "2020-02-23T00:00:00", "2020-02-23T00:02:00"), ) analyzer.update_asset_info.assert_called_once() @@ -656,7 +703,8 @@ def test_get_return_report_return_correct_report_with_index(self, mock_plot): self.assertEqual(report[7], 0.093) # 시간 정보 self.assertEqual( - report[8], ("2020-04-30T05:50:00", "2020-04-30T05:51:00", "2020-04-30T05:53:00") + report[8], + ("2020-04-30T05:50:00", "2020-04-30T05:51:00", "2020-04-30T05:53:00"), ) report = analyzer.get_return_report(index_info=(3, 2)) @@ -677,10 +725,13 @@ def test_get_return_report_return_correct_report_with_index(self, mock_plot): self.assertEqual(report[7], 0.197) # 시간 정보 self.assertEqual( - report[8], ("2020-04-30T05:50:00", "2020-04-30T05:56:00", "2020-04-30T05:58:00") + report[8], + ("2020-04-30T05:50:00", "2020-04-30T05:56:00", "2020-04-30T05:58:00"), ) - report = analyzer.get_return_report(graph_filename="mango_graph.png", index_info=(3, -1)) + report = analyzer.get_return_report( + graph_filename="mango_graph.png", index_info=(3, -1) + ) self.assertEqual(len(report), 9) # 입금 자산 @@ -698,14 +749,17 @@ def test_get_return_report_return_correct_report_with_index(self, mock_plot): self.assertEqual(report[7], 0.413) # 시간 정보 self.assertEqual( - report[8], ("2020-04-30T05:50:00", "2020-04-30T05:57:00", "2020-04-30T05:59:00") + report[8], + ("2020-04-30T05:50:00", "2020-04-30T05:57:00", "2020-04-30T05:59:00"), ) analyzer.update_asset_info.assert_called() @patch("mplfinance.make_addplot") @patch("mplfinance.plot") - def test_get_return_report_draw_graph_when_graph_filename_exist(self, mock_plot, mock_addplot): + def test_get_return_report_draw_graph_when_graph_filename_exist( + self, mock_plot, mock_addplot + ): """ { cumulative_return: 기준 시점부터 누적 수익률 @@ -741,7 +795,8 @@ def test_get_return_report_draw_graph_when_graph_filename_exist(self, mock_plot, self.assertEqual(report[7], -65.248) # 시간 정보 self.assertEqual( - report[8], ("2020-02-23T00:00:00", "2020-02-23T00:00:00", "2020-02-23T00:02:00") + report[8], + ("2020-02-23T00:00:00", "2020-02-23T00:00:00", "2020-02-23T00:02:00"), ) analyzer.update_asset_info.assert_called_once() @@ -833,7 +888,10 @@ def test_create_report_return_correct_report( "balance": 5000, "cumulative_return": -65.248, "price_change_ratio": {"mango": -50.0, "apple": 50.0}, - "asset": [("mango", 500, 300, 5.23, -40.0), ("apple", 250, 750, 2.11, 200.0)], + "asset": [ + ("mango", 500, 300, 5.23, -40.0), + ("apple", 250, 750, 2.11, 200.0), + ], "date_time": "2020-02-23T00:00:00", "kind": 3, } @@ -841,7 +899,10 @@ def test_create_report_return_correct_report( "balance": 5000, "cumulative_return": -75.067, "price_change_ratio": {"mango": -66.667, "apple": -99.85}, - "asset": [("mango", 600, 200, 4.23, -66.667), ("apple", 500, 0.75, 3.11, -99.85)], + "asset": [ + ("mango", 600, 200, 4.23, -66.667), + ("apple", 500, 0.75, 3.11, -99.85), + ], "date_time": "2020-02-23T00:01:00", "kind": 3, } @@ -887,7 +948,9 @@ def test_create_report_return_correct_report( self.assertEqual(report["summary"][3]["apple"], -99.85) self.assertEqual(report["summary"][4], None) - self.assertEqual(report["summary"][5], "2020-02-23T00:00:00 - 2020-02-23T00:02:00") + self.assertEqual( + report["summary"][5], "2020-02-23T00:00:00 - 2020-02-23T00:02:00" + ) self.assertEqual(report["summary"][6], -75.067) self.assertEqual(report["summary"][7], -65.248) # 시간 정보 @@ -898,7 +961,9 @@ def test_create_report_return_correct_report( analyzer._get_rss_memory.assert_called_once() @patch("mplfinance.plot") - def test_create_report_call_update_info_func_with_asset_type_and_callback(self, mock_plot): + def test_create_report_call_update_info_func_with_asset_type_and_callback( + self, mock_plot + ): analyzer = Analyzer() analyzer.initialize("mango") analyzer.update_asset_info = MagicMock() @@ -922,7 +987,9 @@ def test_create_report_create_correct_report_file( tag = "orange" filename = "mango" report = analyzer.create_report() - mock_file.assert_called_with(analyzer.OUTPUT_FOLDER + "untitled-report.txt", "w") + mock_file.assert_called_with( + analyzer.OUTPUT_FOLDER + "untitled-report.txt", "w" + ) handle = mock_file() expected = [ "### TRADING TABLE =================================\n", @@ -958,7 +1025,9 @@ def test_create_report_create_correct_report_file( @patch("mplfinance.make_addplot") @patch("mplfinance.plot") @patch("builtins.open", new_callable=mock_open) - def test_create_report_draw_correct_graph(self, mock_file, mock_plot, mock_make_addplot): + def test_create_report_draw_correct_graph( + self, mock_file, mock_plot, mock_make_addplot + ): analyzer = Analyzer() analyzer._get_rss_memory = MagicMock(return_value=123.45678) analyzer.initialize("mango") @@ -991,7 +1060,9 @@ def test_create_report_draw_correct_graph(self, mock_file, mock_plot, mock_make_ mav=analyzer.sma_info, style="starsandstripes", savefig=dict( - fname=analyzer.OUTPUT_FOLDER + filename + ".jpg", dpi=300, pad_inches=0.25 + fname=analyzer.OUTPUT_FOLDER + filename + ".jpg", + dpi=300, + pad_inches=0.25, ), figscale=1.25, ) @@ -1038,7 +1109,9 @@ def test_create_report_draw_correct_graph_when_rsi_enabled( mav=analyzer.sma_info, style="starsandstripes", savefig=dict( - fname=analyzer.OUTPUT_FOLDER + filename + ".jpg", dpi=300, pad_inches=0.25 + fname=analyzer.OUTPUT_FOLDER + filename + ".jpg", + dpi=300, + pad_inches=0.25, ), figscale=1.25, ) diff --git a/tests/binance_data_provider_test.py b/tests/binance_data_provider_test.py index 66de83a..45a33bd 100644 --- a/tests/binance_data_provider_test.py +++ b/tests/binance_data_provider_test.py @@ -72,6 +72,7 @@ def test_get_info_should_return_correct_data(self, mock_get): ] ] expected = { + "type": "primary_candle", "market": "BTC", "date_time": "2017-07-03T09:00:00", "opening_price": 0.0163479, @@ -83,4 +84,4 @@ def test_get_info_should_return_correct_data(self, mock_get): } data_provider = BinanceDataProvider("BTC", 60) data = data_provider.get_info() - self.assertEqual(data, expected) + self.assertEqual(data[0], expected) diff --git a/tests/bithumb_data_provider_test.py b/tests/bithumb_data_provider_test.py index e6d09a4..a21726f 100644 --- a/tests/bithumb_data_provider_test.py +++ b/tests/bithumb_data_provider_test.py @@ -23,14 +23,14 @@ def test_get_info_return_data_correctly(self, mock_get): info = dp.get_info() - self.assertEqual(info["market"], "BTC") - self.assertEqual(info["date_time"], "2021-05-01T22:08:00") - self.assertEqual(info["opening_price"], 68934000) - self.assertEqual(info["high_price"], 68980000) - self.assertEqual(info["low_price"], 68914000) - self.assertEqual(info["closing_price"], 68933000) - self.assertEqual(info["acc_price"], 0) - self.assertEqual(info["acc_volume"], 0.69114496) + self.assertEqual(info[0]["market"], "BTC") + self.assertEqual(info[0]["date_time"], "2021-05-01T22:08:00") + self.assertEqual(info[0]["opening_price"], 68934000) + self.assertEqual(info[0]["high_price"], 68980000) + self.assertEqual(info[0]["low_price"], 68914000) + self.assertEqual(info[0]["closing_price"], 68933000) + self.assertEqual(info[0]["acc_price"], 0) + self.assertEqual(info[0]["acc_volume"], 0.69114496) mock_get.assert_called_once_with(dp.url) self.assertEqual(dp.url, "https://api.bithumb.com/public/candlestick/BTC_KRW/1m") diff --git a/tests/simulation_data_provider_test.py b/tests/simulation_data_provider_test.py index 4470afa..6c9d437 100644 --- a/tests/simulation_data_provider_test.py +++ b/tests/simulation_data_provider_test.py @@ -30,7 +30,7 @@ def test_get_info_return_next_data_correctly(self): dp = SimulationDataProvider() dp.index = 0 dp.data = dummy_data - self.assertEqual(dp.get_info(), dummy_data[0]) - self.assertEqual(dp.get_info(), dummy_data[1]) - self.assertEqual(dp.get_info(), dummy_data[2]) + self.assertEqual(dp.get_info()[0], dummy_data[0]) + self.assertEqual(dp.get_info()[0], dummy_data[1]) + self.assertEqual(dp.get_info()[0], dummy_data[2]) self.assertEqual(dp.get_info(), None) diff --git a/tests/strategy_bnh_test.py b/tests/strategy_bnh_test.py index 583c6cf..6ad1fea 100644 --- a/tests/strategy_bnh_test.py +++ b/tests/strategy_bnh_test.py @@ -26,8 +26,15 @@ def test_initialize_update_initial_balance(self): def test_update_trading_info_append_info_to_data(self): bnh = StrategyBuyAndHold() bnh.initialize(100, 10) - bnh.update_trading_info("mango") - self.assertEqual(bnh.data.pop(), "mango") + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + }] + bnh.update_trading_info(dummy_info) + self.assertEqual(bnh.data.pop(), { + "type": "primary_candle", + "market": "orange", + }) def test_update_trading_info_ignore_info_when_not_yet_initialzed(self): bnh = StrategyBuyAndHold() @@ -169,27 +176,16 @@ def test_get_request_return_None_when_data_is_invaild(self): request = bnh.get_request() self.assertEqual(request, None) - def test_get_request_return_turn_over_when_last_data_is_None(self): - bnh = StrategyBuyAndHold() - bnh.initialize(50000, 100) - dummy_info = {} - dummy_info["closing_price"] = 20000000 - bnh.update_trading_info(dummy_info) - requests = bnh.get_request() - self.assertEqual(requests[0]["price"], 20000000) - self.assertEqual(requests[0]["amount"], 0.0005) - self.assertEqual(requests[0]["type"], "buy") - bnh.update_trading_info(None) - requests = bnh.get_request() - self.assertEqual(requests, None) - def test_get_request_return_turn_over_when_target_budget_is_too_small_at_simulation(self): bnh = StrategyBuyAndHold() bnh.initialize(100, 100) bnh.is_simulation = True - dummy_info = {} - dummy_info["date_time"] = "2020-02-25T15:41:09" - dummy_info["closing_price"] = 20000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000 + }] bnh.update_trading_info(dummy_info) requests = bnh.get_request() self.assertEqual(requests[0]["price"], 0) @@ -198,8 +194,11 @@ def test_get_request_return_turn_over_when_target_budget_is_too_small_at_simulat def test_get_request_use_balance_when_balance_is_smaller_than_target_budget(self): bnh = StrategyBuyAndHold() bnh.initialize(1000, 10) - dummy_info = {} - dummy_info["closing_price"] = 20000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "closing_price": 20000 + }] bnh.update_trading_info(dummy_info) bnh.balance = 100 requests = bnh.get_request() @@ -209,8 +208,11 @@ def test_get_request_use_balance_when_balance_is_smaller_than_target_budget(self def test_get_request_return_None_when_balance_is_smaller_than_total_value(self): bnh = StrategyBuyAndHold() bnh.initialize(5000, 10) - dummy_info = {} - dummy_info["closing_price"] = 62000000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "closing_price": 20000000 + }] bnh.update_trading_info(dummy_info) bnh.balance = 10000 requests = bnh.get_request() @@ -222,9 +224,12 @@ def test_get_request_return_turn_over_when_balance_is_smaller_than_min_price_at_ bnh = StrategyBuyAndHold() bnh.initialize(900, 10) bnh.is_simulation = True - dummy_info = {} - dummy_info["date_time"] = "2020-02-25T15:41:09" - dummy_info["closing_price"] = 20000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000 + }] bnh.update_trading_info(dummy_info) bnh.balance = 9.5 requests = bnh.get_request() @@ -235,8 +240,11 @@ def test_get_request_return_None_when_balance_is_smaller_than_min_price(self): bnh = StrategyBuyAndHold() bnh.initialize(900, 10) bnh.is_simulation = False - dummy_info = {} - dummy_info["closing_price"] = 20000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "closing_price": 20000 + }] bnh.update_trading_info(dummy_info) bnh.balance = 9.5 requests = bnh.get_request() @@ -245,8 +253,11 @@ def test_get_request_return_None_when_balance_is_smaller_than_min_price(self): def test_get_request_return_correct_request(self): bnh = StrategyBuyAndHold() bnh.initialize(50000, 100) - dummy_info = {} - dummy_info["closing_price"] = 20000000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "closing_price": 20000000 + }] bnh.update_trading_info(dummy_info) requests = bnh.get_request() self.assertEqual(requests[0]["price"], 20000000) @@ -258,8 +269,11 @@ def test_get_request_return_correct_request_with_cancel_requests(self): bnh.initialize(50000, 100) bnh.waiting_requests["mango_id"] = {"request": {"id": "mango_id"}} bnh.waiting_requests["orange_id"] = {"request": {"id": "orange_id"}} - dummy_info = {} - dummy_info["closing_price"] = 20000000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "closing_price": 20000000 + }] bnh.update_trading_info(dummy_info) requests = bnh.get_request() @@ -277,15 +291,18 @@ def test_get_request_return_same_datetime_at_simulation(self): bnh = StrategyBuyAndHold() bnh.initialize(1000, 100) bnh.is_simulation = True - dummy_info = {} - dummy_info["date_time"] = "2020-02-25T15:41:09" - dummy_info["closing_price"] = 20000000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000000 + }] bnh.update_trading_info(dummy_info) requests = bnh.get_request() self.assertEqual(requests[0]["date_time"], "2020-02-25T15:41:09") - dummy_info["date_time"] = "2020-02-25T23:59:59" - dummy_info["closing_price"] = 20000000 + dummy_info[0]["date_time"] = "2020-02-25T23:59:59" + dummy_info[0]["closing_price"] = 20000000 bnh.update_trading_info(dummy_info) requests = bnh.get_request() self.assertEqual(requests[0]["date_time"], "2020-02-25T23:59:59") diff --git a/tests/strategy_rsi_test.py b/tests/strategy_rsi_test.py index ec42f45..b10632f 100644 --- a/tests/strategy_rsi_test.py +++ b/tests/strategy_rsi_test.py @@ -26,11 +26,14 @@ def test_initialize_update_initial_balance(self): def test_update_trading_info_append_info_to_data(self): sma = StrategyRsi() sma.initialize(100, 10) - dummy_info = { - "closing_price": 500, - } + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 500 + }] sma.update_trading_info(dummy_info) - self.assertEqual(sma.data.pop(), dummy_info) + self.assertEqual(sma.data.pop(), dummy_info[0]) def test_update_trading_info_ignore_info_when_not_yet_initialzed(self): sma = StrategyRsi() @@ -162,7 +165,12 @@ def test_get_request_return_None_when_data_is_empty(self): def test_get_request_return_correct_request_at_buy_position(self): sma = StrategyRsi() sma.initialize(10000, 100) - dummy_info = {"closing_price": 20000000} + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000000 + }] sma.update_trading_info(dummy_info) sma.position = "buy" requests = sma.get_request() @@ -173,7 +181,12 @@ def test_get_request_return_correct_request_at_buy_position(self): def test_get_request_return_correct_request_at_sell_position(self): sma = StrategyRsi() sma.initialize(10000, 100) - dummy_info = {"closing_price": 12345678} + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 12345678 + }] sma.update_trading_info(dummy_info) sma.position = "sell" sma.asset_amount = 0.001 @@ -187,9 +200,12 @@ def test_get_request_return_request_with_cancel_requests(self): sma.initialize(10000, 100) sma.waiting_requests["mango_id"] = {"request": {"id": "mango_id"}} sma.waiting_requests["orange_id"] = {"request": {"id": "orange_id"}} - dummy_info = {} - dummy_info["date_time"] = "2020-02-25T15:41:09" - dummy_info["closing_price"] = 20000000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000000 + }] sma.update_trading_info(dummy_info) sma.position = "sell" sma.asset_amount = 60 diff --git a/tests/strategy_sma_0_test.py b/tests/strategy_sma_0_test.py index 4895c9e..abf8072 100644 --- a/tests/strategy_sma_0_test.py +++ b/tests/strategy_sma_0_test.py @@ -26,18 +26,24 @@ def test_initialize_update_initial_balance(self): def test_update_trading_info_append_info_to_data(self): sma = StrategySma0() sma.initialize(100, 10) - dummy_info = { - "closing_price": 500, - } + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 500 + }] sma.update_trading_info(dummy_info) - self.assertEqual(sma.data.pop(), dummy_info) + self.assertEqual(sma.data.pop(), dummy_info[0]) def test_update_trading_info_append_closing_price(self): sma = StrategySma0() sma.initialize(100, 10) - dummy_info = { - "closing_price": 500, - } + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 500 + }] sma.update_trading_info(dummy_info) self.assertEqual(sma.closing_price_list.pop(), 500) @@ -73,10 +79,12 @@ class DummyMean: series_return.rolling.return_value = rolling_return_mock mock_series.return_value = series_return - dummy_info = { - "date_time": "mango", - "closing_price": 500, - } + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 500 + }] mock_np.return_value = False sma.initialize(100, 10) sma.current_process = "buy" @@ -129,10 +137,12 @@ class DummyMean: series_return.rolling.return_value = rolling_return_mock mock_series.return_value = series_return - dummy_info = { - "date_time": "mango", - "closing_price": 500, - } + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 500 + }] mock_np.return_value = False sma.initialize(100, 10) sma.current_process = "sell" @@ -193,10 +203,12 @@ class DummyMean: series_return.rolling.return_value = rolling_return_mock mock_series.return_value = series_return - dummy_info = { - "date_time": "dummy_datetime", - "closing_price": 500, - } + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 500 + }] mock_np.return_value = False sma.initialize(100, 10) sma.current_process = "sell" @@ -356,7 +368,12 @@ def test_get_request_return_None_when_cross_info_is_invaild(self): def test_get_request_return_correct_request_at_buy_process(self): sma = StrategySma0() sma.initialize(10000, 100) - dummy_info = {"closing_price": 20000000} + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000000 + }] sma.update_trading_info(dummy_info) sma.cross_info[0] = {"price": 500, "index": 1} sma.cross_info[1] = {"price": 500, "index": 2} @@ -367,14 +384,24 @@ def test_get_request_return_correct_request_at_buy_process(self): self.assertEqual(requests[0]["amount"], 0.0001) self.assertEqual(requests[0]["type"], "buy") - dummy_info = {"closing_price": 10000000} + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 10000000 + }] sma.update_trading_info(dummy_info) requests = sma.get_request() self.assertEqual(requests[0]["price"], 10000000) self.assertEqual(requests[0]["amount"], 0.0003) self.assertEqual(requests[0]["type"], "buy") - dummy_info = {"closing_price": 100} + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 100 + }] sma.update_trading_info(dummy_info) sma.balance = 2000 requests = sma.get_request() @@ -385,7 +412,12 @@ def test_get_request_return_correct_request_at_buy_process(self): def test_get_request_return_correct_request_at_sell_process(self): sma = StrategySma0() sma.initialize(10000, 100) - dummy_info = {"closing_price": 20000000} + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000000 + }] sma.update_trading_info(dummy_info) sma.cross_info[0] = {"price": 500, "index": 1} sma.cross_info[1] = {"price": 500, "index": 2} @@ -398,7 +430,12 @@ def test_get_request_return_correct_request_at_sell_process(self): self.assertEqual(requests[0]["amount"], 20) self.assertEqual(requests[0]["type"], "sell") - dummy_info = {"closing_price": 10000000} + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 10000000 + }] sma.update_trading_info(dummy_info) sma.asset_amount = 10 requests = sma.get_request() @@ -414,9 +451,12 @@ def test_get_request_return_request_with_cancel_requests(self): sma.waiting_requests["mango_id"] = {"request": {"id": "mango_id"}} sma.waiting_requests["orange_id"] = {"request": {"id": "orange_id"}} sma.is_simulation = True - dummy_info = {} - dummy_info["date_time"] = "2020-02-25T15:41:09" - dummy_info["closing_price"] = 20000000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000000 + }] sma.update_trading_info(dummy_info) sma.current_process = "sell" sma.asset_amount = 60 @@ -431,33 +471,16 @@ def test_get_request_return_request_with_cancel_requests(self): self.assertEqual(requests[2]["type"], "sell") self.assertEqual(requests[2]["date_time"], "2020-02-25T15:41:09") - def test_get_request_return_turn_over_when_last_data_is_None(self): - sma = StrategySma0() - sma.initialize(10000, 100) - sma.cross_info[0] = {"price": 500, "index": 1} - sma.cross_info[1] = {"price": 500, "index": 2} - dummy_info = {} - dummy_info["closing_price"] = 20000000 - sma.update_trading_info(dummy_info) - sma.current_process = "buy" - sma.process_unit = (4000, 0) - requests = sma.get_request() - self.assertEqual(requests[0]["price"], 20000000) - self.assertEqual(requests[0]["amount"], 0.0001) - self.assertEqual(requests[0]["type"], "buy") - - sma.update_trading_info(None) - requests = sma.get_request() - self.assertEqual(requests[0]["price"], 0) - self.assertEqual(requests[0]["amount"], 0) - def test_get_request_return_turn_over_when_target_budget_lt_min_price_at_simulation(self): sma = StrategySma0() sma.initialize(1000, 500) sma.is_simulation = True - dummy_info = {} - dummy_info["date_time"] = "2020-02-25T15:41:09" - dummy_info["closing_price"] = 20000000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000000 + }] sma.update_trading_info(dummy_info) sma.current_process = "buy" sma.process_unit = (300, 0) @@ -472,9 +495,12 @@ def test_get_request_return_turn_over_when_asset_amount_empty_at_simulation(self sma.cross_info[0] = {"price": 500, "index": 1} sma.cross_info[1] = {"price": 500, "index": 2} sma.is_simulation = True - dummy_info = {} - dummy_info["date_time"] = "2020-02-25T15:41:09" - dummy_info["closing_price"] = 20000 + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 20000 + }] sma.update_trading_info(dummy_info) sma.current_process = "sell" sma.asset_amount = 0 diff --git a/tests/strategy_sma_ml_test.py b/tests/strategy_sma_ml_test.py index f1a781c..1b79e5e 100644 --- a/tests/strategy_sma_ml_test.py +++ b/tests/strategy_sma_ml_test.py @@ -26,11 +26,14 @@ def test_initialize_update_initial_balance(self): def test_update_trading_info_append_info_to_data(self): sma = StrategySmaMl() sma.initialize(100, 10) - dummy_info = { - "closing_price": 500, - } + dummy_info = [{ + "type": "primary_candle", + "market": "orange", + "date_time": "2020-02-25T15:41:09", + "closing_price": 500 + }] sma.update_trading_info(dummy_info) - self.assertEqual(sma.data.pop(), dummy_info) + self.assertEqual(sma.data.pop(), dummy_info[0]) def test_update_trading_info_ignore_info_when_not_yet_initialzed(self): sma = StrategySmaMl() diff --git a/tests/upbit_data_provider_test.py b/tests/upbit_data_provider_test.py index a9b1e81..709f2bb 100644 --- a/tests/upbit_data_provider_test.py +++ b/tests/upbit_data_provider_test.py @@ -34,14 +34,14 @@ def test_get_info_return_data_correctly(self, mock_get): info = dp.get_info() - self.assertEqual(info["market"], "BTC") - self.assertEqual(info["date_time"], "2020-03-10T22:52:00") - self.assertEqual(info["opening_price"], 9777000) - self.assertEqual(info["high_price"], 9778000) - self.assertEqual(info["low_price"], 9763000) - self.assertEqual(info["closing_price"], 9778000) - self.assertEqual(info["acc_price"], 11277224.71063000) - self.assertEqual(info["acc_volume"], 1.15377852) + self.assertEqual(info[0]["market"], "BTC") + self.assertEqual(info[0]["date_time"], "2020-03-10T22:52:00") + self.assertEqual(info[0]["opening_price"], 9777000) + self.assertEqual(info[0]["high_price"], 9778000) + self.assertEqual(info[0]["low_price"], 9763000) + self.assertEqual(info[0]["closing_price"], 9778000) + self.assertEqual(info[0]["acc_price"], 11277224.71063000) + self.assertEqual(info[0]["acc_volume"], 1.15377852) mock_get.assert_called_once_with(dp.URL, params={"market": "KRW-BTC", "count": 1}) @patch("requests.get")