Commit bf40eee2 authored by 纪超's avatar 纪超

添加信号模块

parent 4fa60d2f
......@@ -367,7 +367,7 @@ class DriftSolver(ABC):
pass
class SignalBuilder(ABC):
class RebalanceSignal(ABC):
'''
控制信号,发起是否调仓服务
'''
......@@ -386,17 +386,26 @@ class SignalBuilder(ABC):
pass
class RebalanceBuilder(ABC):
class RebalanceRuler(ABC):
'''
再平衡构建器
再平衡信号分配器,根据既定的规则,再众多信号中,选出进行再平衡的信号
'''
@abstractmethod
def get_rebalance(self, day, risk: PortfoliosRisk):
def take_next_signal(self, day, risk: PortfoliosRisk):
'''
获取指定日期,指定风险等级的再平衡数据
取出指定日期,指定风险等级的再平衡信号数据,注意取出消费后,无法退回,非幂等函数
:param day: 指定日期
:param risk: 指定风险等级
:return: 再平衡数据
:return: 如果存在,则返回取出的再平衡信号信息,否则返回None
'''
pass
@abstractmethod
def cancel_signal(self, sign_id):
'''
取消信号ID为已消费状态,即设置信号为未消费状态
:param sign_id: 信号ID
:return 取消成功则返回True, 否则返回False
'''
pass
......@@ -76,6 +76,7 @@ asset-pool:
portfolios:
holder:
init-nav: 100
min-interval-days: 10
solver:
tol: 1E-10
navs:
......@@ -119,7 +120,7 @@ rebalance:
init-factor: 0.000000002
high-weight:
coef: 0.2
builder:
ruler:
disable-period: #自然日
normal: 10
crisis_1: 15
......
from framework import component, autowired
from api import PortfoliosHolder, PortfoliosRisk, RebalanceBuilder
from api import PortfoliosHolder, PortfoliosRisk, RebalanceRuler
from portfolios.dao import robo_hold_portfolios as rhp
import json
......@@ -8,7 +8,7 @@ import json
class NextReblanceHolder(PortfoliosHolder):
@autowired
def __init__(self, rebalance: RebalanceBuilder):
def __init__(self, rebalance: RebalanceRuler):
self._rebalance = rebalance
def get_portfolios_weight(self, day, risk: PortfoliosRisk):
......
from abc import ABC, abstractmethod
from api import SignalBuilder, PortfoliosBuilder, PortfoliosRisk
from api import RebalanceSignal, PortfoliosBuilder, PortfoliosRisk
from framework import autowired
from rebalance.dao import robo_rebalance_signal as rrs
class BaseSignalBuilder(SignalBuilder, ABC):
class BaseRebalanceSignal(RebalanceSignal, ABC):
@autowired
def __init__(self, builder: PortfoliosBuilder = None):
......
from framework import component, autowired, get_config
from api import RebalanceBuilder, PortfoliosRisk, SignalBuilder, SignalType, PortfoliosType
from api import RebalanceRuler, PortfoliosRisk, RebalanceSignal, SignalType, PortfoliosType
from typing import List
from rebalance.dao import robo_rebalance_signal as rrs
@component
class LevelRebalanceBuilder(RebalanceBuilder):
class LevelRebalanceRuler(RebalanceRuler):
'''
定义:
1.定义所有调仓类型为非NORMAL类型的信号为清仓信号
2.定义所有调仓类型为NORMAL类型的信号为加仓信号
3.定义持久信号为上次选用调仓的信号时间到当前时间内,该信号都有效
4.定义临时信号为仅当天有效
规则:
1.所有清仓信号为持久信号,所有加仓信号为临时信号
2.对于持久信号规则如下:
2.1 上一次选用信号到当前时间内,是否有持久信号
2.2 如果有,则看级别是否高于上一次选用信号
2.3 如果高于,则输出该信号
3.如果没有持久信号,则从临时信号中根据级别排序找出第一个,作为输出信号
'''
@autowired
def __init__(self, signals: List[SignalBuilder] = None):
def __init__(self, signals: List[RebalanceSignal] = None):
self._signals = signals
self._config = get_config(__name__)
......@@ -17,7 +31,7 @@ class LevelRebalanceBuilder(RebalanceBuilder):
result = self._config['disable-period']
return {PortfoliosType(x[0]): x[1] for x in result.items()}
def get_rebalance(self, day, risk: PortfoliosRisk):
def take_next_signal(self, day, risk: PortfoliosRisk):
last_re = rrs.get_last_one(max_date=day, risk=risk, effective=True)
if last_re and last_re['date'] == day:
return last_re
......@@ -31,4 +45,5 @@ class LevelRebalanceBuilder(RebalanceBuilder):
return use_signal
return None
def cancel_signal(self, sign_id):
pass
......@@ -5,11 +5,11 @@ from dateutil.relativedelta import relativedelta
from api import PortfoliosRisk, SignalType, Navs
from framework import get_config, autowired, component
from rebalance.base_signal import BaseSignalBuilder
from rebalance.base_signal import BaseRebalanceSignal
from rebalance.dao import robo_rebalance_signal as rrs
class CrisisSignal(BaseSignalBuilder, ABC):
class CrisisSignal(BaseRebalanceSignal, ABC):
@autowired
def __init__(self, navs: Navs = None):
......@@ -58,7 +58,7 @@ class CrisisSignal(BaseSignalBuilder, ABC):
@component(bean_name='crisis_one')
class CrisisOneSignal(CrisisSignal, BaseSignalBuilder):
class CrisisOneSignal(CrisisSignal, BaseRebalanceSignal):
@property
def consecut_days(self):
......@@ -84,7 +84,7 @@ class CrisisOneSignal(CrisisSignal, BaseSignalBuilder):
@component(bean_name='crisis_two')
class CrisisTwoSignal(CrisisSignal, BaseSignalBuilder):
class CrisisTwoSignal(CrisisSignal, BaseRebalanceSignal):
@property
def negative_growth_years(self):
......
from api import PortfoliosRisk, SignalType, Datum, PortfoliosHolder, DriftSolver
from framework import component, autowired, get_config
from rebalance.base_signal import BaseSignalBuilder
from rebalance.base_signal import BaseRebalanceSignal
from rebalance.dao import robo_rebalance_signal as rrs
@component(bean_name='curve-drift')
class CurveDrift(BaseSignalBuilder):
class CurveDrift(BaseRebalanceSignal):
@autowired(names={'solver': 'date-curve'})
def __init__(self, datum: Datum = None, hold: PortfoliosHolder = None, solver: DriftSolver = None):
......
......@@ -2,12 +2,12 @@ import pandas as pd
from api import PortfoliosBuilder, SignalType, PortfoliosRisk, Datum, DriftSolver
from framework import component, autowired, get_config, filter_weekend, next_workday, is_workday
from rebalance.base_signal import BaseSignalBuilder
from rebalance.base_signal import BaseRebalanceSignal
from rebalance.dao import robo_weight_drift as rwd, robo_rebalance_signal as rrs
@component(bean_name='high-buy')
class HighBuySignal(BaseSignalBuilder):
class HighBuySignal(BaseRebalanceSignal):
@autowired(names={'solver': 'high-weight'})
def __init__(self, solver: DriftSolver = None):
......
from api import PortfoliosRisk, SignalType
from framework import component
from rebalance.base_signal import BaseSignalBuilder
from rebalance.base_signal import BaseRebalanceSignal
from rebalance.dao import robo_rebalance_signal as rrs
@component(bean_name='init')
class InitSignalBuilder(BaseSignalBuilder):
class InitSignalBuilder(BaseRebalanceSignal):
@property
def signal_type(self) -> SignalType:
......
......@@ -3,12 +3,12 @@ from scipy.stats import norm
from api import SignalType, PortfoliosRisk, Navs
from framework import component, autowired, get_config
from rebalance.base_signal import BaseSignalBuilder
from rebalance.base_signal import BaseRebalanceSignal
from rebalance.dao import robo_rebalance_signal as rrs
@component(bean_name='market-right')
class MarketRight(BaseSignalBuilder):
class MarketRight(BaseRebalanceSignal):
@autowired
def __init__(self, navs: Navs = None):
......
import unittest
from api import SignalBuilder, PortfoliosRisk, RebalanceBuilder
from api import RebalanceSignal, PortfoliosRisk, RebalanceRuler
from framework import autowired, parse_date, get_logger
......@@ -9,27 +9,27 @@ class RebalanceTest(unittest.TestCase):
logger = get_logger(__name__)
@autowired(names={'builder': 'crisis_one'})
def test_crisis_one(self, builder: SignalBuilder = None):
def test_crisis_one(self, builder: RebalanceSignal = None):
signal = builder.get_signal(parse_date('2022-10-13'), PortfoliosRisk.FT9)
self.logger.info(signal)
@autowired(names={'builder': 'market-right'})
def test_market_right(self, builder: SignalBuilder = None):
def test_market_right(self, builder: RebalanceSignal = None):
signal = builder.get_signal(parse_date('2022-10-13'), PortfoliosRisk.FT9)
self.logger.info(signal)
@autowired(names={'builder': 'curve-drift'})
def test_curve_drift(self, builder: SignalBuilder = None):
def test_curve_drift(self, builder: RebalanceSignal = None):
signal = builder.get_signal(parse_date('2022-11-07'), PortfoliosRisk.FT3)
self.logger.info(signal)
@autowired(names={'builder': 'high-buy'})
def test_high_buy(self, builder: SignalBuilder = None):
def test_high_buy(self, builder: RebalanceSignal = None):
builder.get_signal(parse_date('2022-09-10'), PortfoliosRisk.FT3)
@autowired
def test_rebalance_builder(self, builder: RebalanceBuilder = None):
builder.get_rebalance(parse_date('2022-09-01'), PortfoliosRisk.FT3)
def test_rebalance_builder(self, builder: RebalanceRuler = None):
builder.take_next_signal(parse_date('2022-09-01'), PortfoliosRisk.FT3)
if __name__ == '__main__':
......
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