Commit 7dd0bb99 authored by Dr.李's avatar Dr.李

added tests for target vol executor

parent 0591851d
...@@ -30,3 +30,6 @@ class ExecutorBase(metaclass=abc.ABCMeta): ...@@ -30,3 +30,6 @@ class ExecutorBase(metaclass=abc.ABCMeta):
def set_current(self, current_pos: pd.DataFrame): def set_current(self, current_pos: pd.DataFrame):
self.current_pos = current_pos.copy() self.current_pos = current_pos.copy()
def update(self, data_dict: dict):
pass
...@@ -17,7 +17,7 @@ class NaiveExecutor(ExecutorBase): ...@@ -17,7 +17,7 @@ class NaiveExecutor(ExecutorBase):
def execute(self, target_pos: pd.DataFrame) -> Tuple[float, pd.DataFrame]: def execute(self, target_pos: pd.DataFrame) -> Tuple[float, pd.DataFrame]:
if self.current_pos.empty: if self.current_pos.empty:
turn_over = target_pos.weight.sum() turn_over = target_pos.weight.abs().sum()
else: else:
turn_over = self.calc_turn_over(target_pos, self.current_pos) turn_over = self.calc_turn_over(target_pos, self.current_pos)
self.current_pos = target_pos.copy() self.current_pos = target_pos.copy()
......
...@@ -21,12 +21,18 @@ class TargetVolExecutor(ExecutorBase): ...@@ -21,12 +21,18 @@ class TargetVolExecutor(ExecutorBase):
def execute(self, target_pos: pd.DataFrame) -> Tuple[float, pd.DataFrame]: def execute(self, target_pos: pd.DataFrame) -> Tuple[float, pd.DataFrame]:
if not self.m_vol.isFull(): if not self.m_vol.isFull():
turn_over = self.calc_turn_over(target_pos, self.current_pos) if self.current_pos.empty:
turn_over = target_pos.abs().weight.sum()
else:
turn_over = self.calc_turn_over(target_pos, self.current_pos)
return turn_over, target_pos return turn_over, target_pos
else: else:
c_vol = self.m_vol.result() c_vol = self.m_vol.result()
self.multiplier = c_vol / self.target_vol self.multiplier = c_vol / self.target_vol
candidate_pos = target_pos.copy() candidate_pos = target_pos.copy()
candidate_pos['weight'] = candidate_pos.weight * self.multiplier candidate_pos['weight'] = candidate_pos.weight.values / self.multiplier
turn_over = self.calc_turn_over(candidate_pos, self.current_pos) turn_over = self.calc_turn_over(candidate_pos, self.current_pos)
return turn_over, candidate_pos return turn_over, candidate_pos
def update(self, data_dict: dict):
self.m_vol.push(data_dict)
...@@ -19,7 +19,7 @@ class ThresholdExecutor(ExecutorBase): ...@@ -19,7 +19,7 @@ class ThresholdExecutor(ExecutorBase):
def execute(self, target_pos: pd.DataFrame) -> Tuple[float, pd.DataFrame]: def execute(self, target_pos: pd.DataFrame) -> Tuple[float, pd.DataFrame]:
if self.current_pos.empty: if self.current_pos.empty:
return target_pos.weight.sum(), target_pos return target_pos.weight.abs().sum(), target_pos
else: else:
turn_over = self.calc_turn_over(target_pos, self.current_pos) turn_over = self.calc_turn_over(target_pos, self.current_pos)
......
...@@ -6,13 +6,45 @@ Created on 2017-9-22 ...@@ -6,13 +6,45 @@ Created on 2017-9-22
""" """
import unittest import unittest
from collections import deque
import numpy as np
import pandas as pd
from alphamind.execution.targetvolexecutor import TargetVolExecutor from alphamind.execution.targetvolexecutor import TargetVolExecutor
class TestTargetVolExecutor(unittest.TestCase): class TestTargetVolExecutor(unittest.TestCase):
def test_target_vol_executor(self): def test_target_vol_executor(self):
n = 100
window = 30
target_vol = 0.01
executor = TargetVolExecutor(window=window, target_vol=target_vol)
return_1 = np.random.randn(2000, n) * 0.05
return_2 = np.random.randn(2000, n) * 0.2
return_total = np.concatenate((return_1, return_2))
weigths = np.ones(n) / n
codes = np.array(list(range(n)))
ret_deq = deque(maxlen=window)
for i, row in enumerate(return_total):
pos = pd.DataFrame({'code': codes, 'weight': weigths})
turn_over, executed_pos = executor.execute(pos)
if i >= window:
c_vol = np.std(ret_deq, ddof=1)
executed_pos.equals(pos * target_vol / c_vol)
else:
executed_pos.equals(pos)
executor.set_current(executed_pos)
daily_return = row @ weigths
data_dict = {'return': daily_return}
executor.update(data_dict=data_dict)
ret_deq.append(daily_return)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -30,6 +30,7 @@ from alphamind.tests.model.test_linearmodel import TestLinearModel ...@@ -30,6 +30,7 @@ from alphamind.tests.model.test_linearmodel import TestLinearModel
from alphamind.tests.model.test_loader import TestLoader from alphamind.tests.model.test_loader import TestLoader
from alphamind.tests.execution.test_naiveexecutor import TestNaiveExecutor from alphamind.tests.execution.test_naiveexecutor import TestNaiveExecutor
from alphamind.tests.execution.test_thresholdexecutor import TestThresholdExecutor from alphamind.tests.execution.test_thresholdexecutor import TestThresholdExecutor
from alphamind.tests.execution.test_targetvolexecutor import TestTargetVolExecutor
if __name__ == '__main__': if __name__ == '__main__':
...@@ -51,6 +52,7 @@ if __name__ == '__main__': ...@@ -51,6 +52,7 @@ if __name__ == '__main__':
TestLinearModel, TestLinearModel,
TestLoader, TestLoader,
TestNaiveExecutor, TestNaiveExecutor,
TestThresholdExecutor], TestThresholdExecutor,
TestTargetVolExecutor],
alpha_logger) alpha_logger)
runner.run() runner.run()
...@@ -42,4 +42,4 @@ u."AccountsPayablesTDays",u."AccountsPayablesTRate",u."AdminiExpenseRate",u."ART ...@@ -42,4 +42,4 @@ u."AccountsPayablesTDays",u."AccountsPayablesTRate",u."AdminiExpenseRate",u."ART
left join tiny as t on m.trade_date = t.trade_date and m.code = t.code left join tiny as t on m.trade_date = t.trade_date and m.code = t.code
left join experimental as e on m.trade_date = e.trade_date and m.code = e.code; left join experimental as e on m.trade_date = e.trade_date and m.code = e.code;
create UNIQUE index on full_factor_view (trade_date, code) create UNIQUE index on full_factor_view (trade_date, code);
\ No newline at end of file \ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment