ETF双因子轮动策略:从理论到Python实盘代码完整实现

ETF双因子轮动策略:Python量化实现与回测分析 量化投资是通过数学模型和计算机程序进行投资决策的方法论,其核心原理在于利用历史数据验证策略的有效性。在众多量化策略中,因子投资通过识别能够解释资产收益的风险因子来构建投资组合,具有明确的投资逻辑和可验证性。ETF双因子轮动策略结合动量因子和质量因子,动量因子捕捉市场趋势收益,质量因子控制组合波动风险,这种组合能够适应不同市场环境的变化。从技术价值角度看,该策略通过Python实现完整的量化流水线,包括数据获取、因子计算、回测验证等模块,为个人投资者提供了专业的策略开发框架。在应用场景上,特别适合中长期ETF 阅读详情

那天下午,我盯着屏幕上的券商研报,心里冒出一个念头:这些报告写得天花乱坠,但真正能跑起来的代码在哪里?特别是那个“ETF双因子轮动策略”,听起来很美好——动量因子抓趋势,质量因子控风险,理论上能跑赢市场。但当我真的想复现时,发现报告里只有理念框架,缺少可落地的完整流程。

这不仅仅是写几行Python的问题。从数据获取、因子计算、信号生成,到仓位管理、回测验证、实盘衔接,每个环节都有细节决定成败。更重要的是,很多策略在回测里表现完美,一到实盘就出问题,往往是因为忽略了交易成本、滑点、或者因子计算的时间对齐问题。

所以,我决定把这次复现写成一篇能直接操作的指南。不只是给你代码,更重要的是解释每个步骤为什么要这样设计,哪里容易踩坑,以及如何把一次性的研究代码变成可重复使用的策略框架。

1. 先搞清楚双因子轮动到底在解决什么问题

很多人一看到“双因子”就觉得是高端操作,其实它的核心思想很朴素:用动量因子找到近期表现好的ETF,再用质量因子过滤掉波动过大或基本面不稳的品种,避免追高踩雷。

1.1 动量因子不是简单看涨跌幅

动量因子的常见误解是直接按过去N天的收益率排序。但这样做有两个问题:一是短期噪音大,二是没有考虑不同市场状态下的动量有效性。

更稳妥的做法是结合绝对动量与相对动量:

  • 绝对动量:ETF自身在过去20日、60日的收益率
  • 相对动量:与基准指数(如沪深300)的相对强弱
  • 动量持续性:动量是否在多个时间维度一致
# 示例:动量因子计算框架
def calculate_momentum_factor(etf_data, benchmark_data, windows=[20, 60]):
    momentum_scores = {}
    
    for etf_code in etf_data.keys():
        # 绝对动量
        abs_momentum = []
        for window in windows:
            returns = etf_data[etf_code]['close'].pct_change(window).iloc[-1]
            abs_momentum.append(returns)
        
        # 相对动量(相对于基准)
        rel_momentum = []
        for window in windows:
            etf_return = etf_data[etf_code]['close'].pct_change(window).iloc[-1]
            bench_return = benchmark_data.pct_change(window).iloc[-1]
            rel_momentum.append(etf_return - bench_return)
        
        # 综合动量得分(可根据需要调整权重)
        total_score = (sum(abs_momentum) * 0.6 + sum(rel_momentum) * 0.4) / len(windows)
        momentum_scores[etf_code] = total_score
    
    return momentum_scores

这个框架的好处是,你可以根据不同的市场环境调整权重。比如在牛市中,绝对动量权重可以高一些;在震荡市中,相对动量更重要。

1.2 质量因子真正过滤的是不确定性

质量因子常被简化为"低波动",但其实应该包含更多维度:

  • 波动率:过去60日年化波动率,过滤异常波动的品种
  • 流动性:日均成交金额,避免无法正常买卖
  • 规模:ETF资产规模,过小的有清盘风险
  • 跟踪误差:与标的指数的偏离程度
def calculate_quality_factor(etf_data, windows=60):
    quality_scores = {}
    
    for etf_code in etf_data.keys():
        returns = etf_data[etf_code]['close'].pct_change()
        
        # 年化波动率(负向指标,波动越小得分越高)
        volatility = returns.std() * np.sqrt(252)
        volatility_score = 1 / (1 + volatility)  # 波动率倒数作为得分
        
        # 流动性(日均成交额)
        avg_volume = etf_data[etf_code]['volume'].mean()
        liquidity_score = min(avg_volume / 1e8, 1)  # 归一化处理
        
        # 综合质量得分
        quality_scores[etf_code] = volatility_score * 0.7 + liquidity_score * 0.3
    
    return quality_scores

质量因子的关键不是追求绝对的低波动,而是在动量因子选出的候选标的中,剔除风险过高的品种。

1.3 双因子结合的关键是权重动态调整

单纯把两个因子得分加权平均是最简单的做法,但更好的方式是根据市场状态动态调整因子权重:

def dynamic_factor_weighting(market_status):
    """根据市场状态调整因子权重"""
    if market_status == 'bull':
        # 牛市中动量因子权重更高
        return {'momentum': 0.7, 'quality': 0.3}
    elif market_status == 'bear':
        # 熊市中质量因子权重更高
        return {'momentum': 0.3, 'quality': 0.7}
    else:
        # 震荡市均衡配置
        return {'momentum': 0.5, 'quality': 0.5}

市场状态的判断可以用简单的均线系统,比如沪深300指数在20日均线上方为牛市,下方为熊市,震荡区间为震荡市。

2. 数据获取与处理的工程化细节

策略失效的常见原因不是逻辑问题,而是数据问题。特别是时间对齐、复权处理、异常值过滤这些细节。

2.1 构建稳定的数据获取管道

直接从交易软件获取数据虽然方便,但长期运行不稳定。建议使用专业的量化数据接口,并建立本地缓存机制:

import pandas as pd
import os
from datetime import datetime, timedelta

class ETFDataPipeline:
    def __init__(self, data_dir='./etf_data'):
        self.data_dir = data_dir
        os.makedirs(data_dir, exist_ok=True)
    
    def get_etf_list(self):
        """获取ETF基础信息列表"""
        # 这里可以维护一个核心ETF池
        etf_pool = {
            '510300': '沪深300ETF',
            '510500': '中证500ETF', 
            '512100': '中证1000ETF',
            '512880': '证券ETF',
            '515000': '科技ETF',
            # ... 其他ETF
        }
        return etf_pool
    
    def download_daily_data(self, etf_code, start_date, end_date):
        """下载日线数据并缓存"""
        cache_file = f"{self.data_dir}/{etf_code}_{start_date}_{end_date}.csv"
        
        if os.path.exists(cache_file):
            # 从缓存读取
            data = pd.read_csv(cache_file, index_col='date', parse_dates=True)
            return data
        
        # 实际数据获取逻辑(需要接入具体数据源)
        data = self._fetch_from_api(etf_code, start_date, end_date)
        
        # 保存到缓存
        data.to_csv(cache_file)
        return data
    
    def validate_data_quality(self, data):
        """验证数据质量"""
        checks = []
        
        # 检查缺失值
        missing_ratio = data.isnull().sum() / len(data)
        checks.append(missing_ratio.max() < 0.05)  # 缺失率低于5%
        
        # 检查价格连续性
        price_changes = data['close'].pct_change().abs()
        extreme_moves = (price_changes > 0.2).sum()  # 单日涨跌幅超过20%的次数
        checks.append(extreme_moves < len(data) * 0.01)  # 异常波动少于1%
        
        return all(checks)

注意:数据获取一定要考虑复权处理。ETF会有分红再投资,使用前复权数据能更准确反映真实收益。

2.2 处理时间对齐和幸存者偏差

回测中常见的问题是使用未来数据。确保每个时间点只能使用当时已经存在的数据:

def avoid_lookahead_bias(etf_data, current_date):
    """避免使用未来数据"""
    valid_etfs = {}
    
    for etf_code, data in etf_data.items():
        # 只使用在当前日期之前已经上市且有足够历史数据的ETF
        if data.index[0] < current_date - timedelta(days=100):  # 至少100天历史
            historical_data = data[data.index <= current_date]
            if len(historical_data) >= 60:  # 至少有60天数据用于计算因子
                valid_etfs[etf_code] = historical_data
    
    return valid_etfs

2.3 数据异常值处理

市场数据中常有异常值,需要稳健的处理方法:

def robust_data_cleaning(data, method='iqr'):
    """稳健的数据清洗"""
    cleaned_data = data.copy()
    
    if method == 'iqr':
        # IQR方法处理异常值
        Q1 = data.quantile(0.25)
        Q3 = data.quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        
        # 将异常值限制在边界内
        cleaned_data = data.clip(lower_bound, upper_bound)
    
    return cleaned_data

3. 策略回测的完整实现

回测不是简单的信号模拟,要包含完整的交易闭环。

3.1 构建事件驱动的回测框架

class BacktestEngine:
    def __init__(self, initial_capital=1000000, transaction_cost=0.001):
        self.initial_capital = initial_capital
        self.transaction_cost = transaction_cost  # 交易成本(千分之一)
        self.positions = {}  # 当前持仓
        self.cash = initial_capital  # 现金
        self.portfolio_value = []  # 组合净值记录
        self.trade_log = []  # 交易记录
    
    def run_backtest(self, signals, price_data):
        """运行回测"""
        dates = sorted(signals.keys())
        
        for date in dates:
            current_prices = {}
            for etf in signals[date].keys():
                if etf in price_data and date in price_data[etf].index:
                    current_prices[etf] = price_data[etf].loc[date]['close']
            
            if not current_prices:
                continue
                
            # 执行调仓逻辑
            self.rebalance_portfolio(signals[date], current_prices, date)
            
            # 记录组合净值
            self.record_portfolio_value(current_prices, date)
    
    def rebalance_portfolio(self, target_weights, current_prices, date):
        """组合再平衡"""
        # 计算当前持仓价值
        current_value = self.cash
        for etf, shares in self.positions.items():
            if etf in current_prices:
                current_value += shares * current_prices[etf]
        
        # 计算目标持仓
        target_shares = {}
        for etf, weight in target_weights.items():
            if etf in current_prices:
                target_value = current_value * weight
                target_shares[etf] = target_value // current_prices[etf]
        
        # 执行交易
        self.execute_trades(target_shares, current_prices, date)
    
    def execute_trades(self, target_shares, current_prices, date):
        """执行交易"""
        # 先卖出需要减仓的品种
        for etf, current_shares in self.positions.items():
            target_shares_count = target_shares.get(etf, 0)
            if current_shares > target_shares_count:
                sell_shares = current_shares - target_shares_count
                sell_value = sell_shares * current_prices[etf]
                self.cash += sell_value * (1 - self.transaction_cost)
                self.log_trade(date, etf, 'SELL', sell_shares, current_prices[etf])
        
        # 再买入需要加仓的品种
        for etf, target_shares_count in target_shares.items():
            current_shares = self.positions.get(etf, 0)
            if target_shares_count > current_shares:
                buy_shares = target_shares_count - current_shares
                buy_value = buy_shares * current_prices[etf]
                if self.cash >= buy_value * (1 + self.transaction_cost):
                    self.cash -= buy_value * (1 + self.transaction_cost)
                    self.log_trade(date, etf, 'BUY', buy_shares, current_prices[etf])
        
        # 更新持仓
        self.positions = {k: v for k, v in target_shares.items() if v > 0}

3.2 关键性能指标计算

回测结果不能只看收益率,要全面评估风险调整后收益:

def calculate_performance_metrics(portfolio_values, benchmark_returns, risk_free_rate=0.03):
    """计算关键性能指标"""
    returns = portfolio_values.pct_change().dropna()
    
    metrics = {}
    
    # 年化收益率
    total_return = (portfolio_values.iloc[-1] / portfolio_values.iloc[0] - 1)
    annual_return = (1 + total_return) ** (252/len(returns)) - 1
    metrics['年化收益率'] = annual_return
    
    # 年化波动率
    annual_volatility = returns.std() * np.sqrt(252)
    metrics['年化波动率'] = annual_volatility
    
    # 夏普比率
    sharpe_ratio = (annual_return - risk_free_rate) / annual_volatility
    metrics['夏普比率'] = sharpe_ratio
    
    # 最大回撤
    cumulative_returns = (1 + returns).cumprod()
    peak = cumulative_returns.expanding().max()
    drawdown = (cumulative_returns - peak) / peak
    max_drawdown = drawdown.min()
    metrics['最大回撤'] = max_drawdown
    
    # 相对于基准的Alpha、Beta
    if len(benchmark_returns) == len(returns):
        covariance = returns.cov(benchmark_returns)
        benchmark_variance = benchmark_returns.var()
        beta = covariance / benchmark_variance
        alpha = annual_return - (risk_free_rate + beta * (benchmark_returns.mean()*252 - risk_free_rate))
        metrics['Alpha'] = alpha
        metrics['Beta'] = beta
    
    return metrics

3.3 回测验证的常见陷阱

很多策略在回测中表现完美,实盘却失败,常见原因包括:

  1. 过拟合 :在有限数据上过度优化参数
def avoid_overfitting(returns, n_splits=5):
    """使用时间序列交叉验证避免过拟合"""
    from sklearn.model_selection import TimeSeriesSplit
    
    tscv = TimeSeriesSplit(n_splits=n_splits)
    performance_scores = []
    
    for train_idx, test_idx in tscv.split(returns):
        train_returns = returns.iloc[train_idx]
        test_returns = returns.iloc[test_idx]
        
        # 在训练集上优化参数
        best_params = optimize_parameters(train_returns)
        
        # 在测试集上验证
        test_performance = evaluate_strategy(test_returns, best_params)
        performance_scores.append(test_performance)
    
    return np.mean(performance_scores)
  1. 忽略交易成本 :频繁调仓的成本会侵蚀收益
  2. 幸存者偏差 :只使用现在还存在ETF,忽略了已退市品种

4. 从回测到实盘的工程化改造

研究代码和实盘代码是两回事。实盘需要额外的稳健性设计。

4.1 构建容错机制

class ProductionStrategy:
    def __init__(self, fallback_strategy=None):
        self.fallback_strategy = fallback_strategy  # 备用策略
    
    def generate_signals(self, market_data):
        try:
            # 主策略逻辑
            signals = self.main_strategy(market_data)
            
            # 信号验证
            if self.validate_signals(signals):
                return signals
            else:
                return self.fallback_strategy.generate_signals(market_data)
                
        except Exception as e:
            logging.error(f"策略执行错误: {e}")
            # 返回保守信号或保持现有持仓
            return self.get_conservative_signals()
    
    def validate_signals(self, signals):
        """验证信号合理性"""
        if not signals:
            return False
        
        # 检查权重和为1
        total_weight = sum(signals.values())
        if abs(total_weight - 1.0) > 0.01:  # 允许1%的误差
            return False
        
        # 检查单个权重不超过50%(避免过度集中)
        if max(signals.values()) > 0.5:
            return False
        
        return True

4.2 实盘风控设计

实盘必须包含多层次风控:

class RiskManager:
    def __init__(self, max_position_size=0.3, max_daily_loss=0.05):
        self.max_position_size = max_position_size  # 单品种最大仓位
        self.max_daily_loss = max_daily_loss  # 单日最大损失
        
    def check_position_risk(self, positions, prices):
        """检查持仓风险"""
        total_value = sum(shares * prices[etf] for etf, shares in positions.items())
        
        for etf, shares in positions.items():
            position_value = shares * prices[etf]
            position_size = position_value / total_value
            
            if position_size > self.max_position_size:
                return False, f"{etf}仓位超过限制"
        
        return True, "风险检查通过"
    
    def check_market_condition(self, market_data):
        """检查市场状态"""
        # 监控市场波动率
        recent_volatility = market_data['close'].pct_change().std() * np.sqrt(252)
        
        if recent_volatility > 0.5:  # 年化波动率超过50%
            return "high_volatility", "市场波动过大,建议降低仓位"
        
        return "normal", "市场状态正常"

4.3 监控与日志系统

实盘策略需要完善的监控:

import logging
from datetime import datetime

class StrategyMonitor:
    def __init__(self, strategy_name):
        self.strategy_name = strategy_name
        self.setup_logging()
    
    def setup_logging(self):
        logging.basicConfig(
            filename=f'{self.strategy_name}_{datetime.now().strftime("%Y%m%d")}.log',
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s'
        )
    
    def log_signal_generation(self, signals, timestamp):
        logging.info(f"信号生成: {signals}")
    
    def log_trade_execution(self, trades, execution_prices):
        for trade in trades:
            logging.info(f"交易执行: {trade} @ {execution_prices[trade['etf']]}")
    
    def log_performance(self, portfolio_value, benchmark_value):
        relative_perf = portfolio_value / benchmark_value - 1
        logging.info(f"相对收益: {relative_perf:.2%}")

5. 策略优化与持续改进

一个好的策略不是一成不变的,需要建立持续优化的框架。

5.1 参数敏感度分析

def parameter_sensitivity_analysis(strategy_func, base_params, param_ranges, historical_data):
    """分析参数敏感度"""
    results = []
    
    for param_name, range_values in param_ranges.items():
        param_results = []
        
        for value in range_values:
            test_params = base_params.copy()
            test_params[param_name] = value
            
            # 运行回测
            performance = strategy_func(historical_data, test_params)
            param_results.append({
                'param_value': value,
                'performance': performance
            })
        
        # 分析该参数对性能的影响
        sensitivity = analyze_parameter_sensitivity(param_results)
        results.append({
            'parameter': param_name,
            'sensitivity': sensitivity,
            'optimal_range': find_optimal_range(param_results)
        })
    
    return results

5.2 市场适应性测试

策略在不同市场环境下的表现:

def market_regime_testing(strategy, market_data):
    """测试策略在不同市场环境下的表现"""
    regimes = identify_market_regimes(market_data)
    
    regime_performance = {}
    for regime_name, regime_periods in regimes.items():
        regime_returns = []
        
        for start_date, end_date in regime_periods:
            regime_data = market_data[start_date:end_date]
            returns = strategy.backtest(regime_data)
            regime_returns.append(returns)
        
        regime_performance[regime_name] = {
            '平均收益': np.mean(regime_returns),
            '胜率': len([r for r in regime_returns if r > 0]) / len(regime_returns),
            '收益波动率': np.std(regime_returns)
        }
    
    return regime_performance

5.3 建立策略评估矩阵

用多个维度评估策略质量:

评估维度 指标 目标值 实际值
收益能力 年化收益率 >15%
风险控制 最大回撤 <20%
风险调整收益 夏普比率 >1.0
稳定性 月胜率 >60%
容量 最大资金容量 >1000万
适应性 不同市场环境表现 均衡

这个评估框架帮你避免只看收益的片面评价,全面衡量策略的实战价值。

6. 完整代码框架与使用指南

最后给出可以直接使用的代码框架:

# etf_double_factor.py
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

class ETFDoubleFactorStrategy:
    def __init__(self, momentum_windows=[20, 60], quality_windows=60):
        self.momentum_windows = momentum_windows
        self.quality_windows = quality_windows
        self.data_pipeline = ETFDataPipeline()
    
    def prepare_data(self, start_date, end_date):
        """准备数据"""
        etf_list = self.data_pipeline.get_etf_list()
        market_data = {}
        
        for etf_code in etf_list.keys():
            data = self.data_pipeline.download_daily_data(etf_code, start_date, end_date)
            if self.data_pipeline.validate_data_quality(data):
                market_data[etf_code] = data
        
        return market_data
    
    def calculate_factors(self, market_data, current_date):
        """计算双因子"""
        # 动量因子
        momentum_scores = calculate_momentum_factor(market_data, current_date)
        
        # 质量因子  
        quality_scores = calculate_quality_factor(market_data, current_date)
        
        return momentum_scores, quality_scores
    
    def generate_signals(self, momentum_scores, quality_scores, top_n=5):
        """生成交易信号"""
        # 综合得分
        composite_scores = {}
        for etf in momentum_scores.keys():
            if etf in quality_scores:
                composite_scores[etf] = (
                    momentum_scores[etf] * 0.6 + quality_scores[etf] * 0.4
                )
        
        # 选择得分最高的top_n个ETF
        selected_etfs = sorted(composite_scores.items(), 
                             key=lambda x: x[1], reverse=True)[:top_n]
        
        # 等权重配置
        signals = {etf: 1.0/len(selected_etfs) for etf, score in selected_etfs}
        
        return signals
    
    def run_strategy(self, start_date, end_date, initial_capital=1000000):
        """运行完整策略"""
        # 准备数据
        market_data = self.prepare_data(start_date, end_date)
        
        # 初始化回测引擎
        backtest_engine = BacktestEngine(initial_capital)
        
        # 逐日运行
        current_date = start_date
        all_signals = {}
        
        while current_date <= end_date:
            # 避免使用未来数据
            valid_data = avoid_lookahead_bias(market_data, current_date)
            
            if len(valid_data) >= 10:  # 至少有10个可选ETF
                momentum_scores, quality_scores = self.calculate_factors(valid_data, current_date)
                signals = self.generate_signals(momentum_scores, quality_scores)
                all_signals[current_date] = signals
            
            current_date += timedelta(days=1)
        
        # 运行回测
        backtest_engine.run_backtest(all_signals, market_data)
        
        return backtest_engine.portfolio_value, backtest_engine.trade_log

# 使用示例
if __name__ == "__main__":
    strategy = ETFDoubleFactorStrategy()
    
    # 运行回测
    portfolio_values, trade_log = strategy.run_strategy(
        start_date=datetime(2020, 1, 1),
        end_date=datetime(2023, 12, 31)
    )
    
    # 计算性能指标
    metrics = calculate_performance_metrics(portfolio_values)
    print("策略性能指标:", metrics)

这个框架的价值不在于提供一个"圣杯"策略,而是展示如何把研报理念转化成可执行、可验证、可改进的实盘代码。真正重要的不是双因子模型本身,而是这种从研究到实盘的完整方法论。

在实际使用中,建议先用小资金验证,重点关注策略的稳定性和适应性,而不是追求短期高收益。好的量化策略应该是时间的函数,能够在不同市场环境下持续创造价值。

Python实现ETF双因子轮动策略:动量与波动率因子实战指南 量化投资中的因子模型是通过系统性的指标筛选来获取超额收益的重要方法。其核心原理是基于历史数据挖掘能够预测未来收益的统计规律,通过多因子组合降低单一因子的失效风险。在工程实践中,动量因子和波动率因子是构建轮动策略的经典组合,动量因子捕捉趋势延续效应,波动率因子控制组合风险暴露。这种双因子框架特别适用于ETF轮动场景,能够在大类资产轮动中动态调整持仓。本文以ETF双因子轮动为具体案例,详细展示从数据获取、因子计算到回测分析的完整Python实现流程,为量化开发者提供可直接复用的策略模板。 阅读详情

相关推荐

ETF双因子轮动策略:动量与质量因子的Python实战指南

量化投资通过数学模型和计算机技术实现系统化交易决策,其核心在于因子挖掘与组合优化。动量因子基于行为金融学的趋势延续原理,捕捉资产价格的惯性效应;质量因子则从风险调整角度评估投资的稳健性。在ETF轮动策略中,双因子结合能有效平衡收益与风险:动量因子提供进攻性,识别强势品种;质量因子发挥防御作用,过滤高波动资产。这种多因子框架适用于板块轮动明显的市场环境,通过Python可实现从数据获取、因子计算到组合优化的全流程自动化。本文以ETF双因子轮动为案例,详细解析如何使用AkShare获取数据、Backtrader

weixin_30703911的博客 489

ACM_08

描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复;还知道这个长方形的宽和长,编号、长、宽都是整数;现在要求按照一下方式排序(默认排序规则都是从小到大); 1.按照编号从小到大排序 2.对于编号相等的长方形,按照长方形的长排序; 3.如果编号和长都相同,按照长方形的宽排序; 4.如果编号、长、宽都相同,就只保留一个长方形用于排序,删除多余的长方形;最后排好

William的blog 717

ETF双因子轮动策略Python实战:从数据获取到回测分析完整指南

量化投资中的因子模型是通过系统化方法识别资产价格驱动因素的技术框架。其核心原理在于将投资回报分解为可解释的因子暴露,通过多因子合成构建稳健的投资组合。在工程实践中,动量因子捕捉价格趋势延续效应,质量因子评估资产风险收益特征,两者结合能有效提升策略的稳定性。ETF轮动策略正是基于因子模型的典型应用,通过动态调整不同类别ETF的配置权重,实现在震荡市和结构性行情中的超额收益。本文以Python为技术工具,详细演示了如何构建完整的双因子轮动策略体系,涵盖数据获取、因子计算、策略回测等关键环节,为量化投资爱好者提供

weixin_33749242的博客 380

长方形排序

ACM练习题‘‘一种排序’’

xsm_2017的博客 2066

ETF双因子轮动策略:动量与质量因子的Python量化实战

多因子模型是量化投资中的核心方法论,通过结合多个维度指标来筛选优质资产。其基本原理是从不同角度评估资产表现,动量因子捕捉价格趋势强度,质量因子衡量风险调整后的稳定性。这种技术价值在于能够实现因子间的互补效应,降低单一因子的周期性风险。在资产配置和组合优化等应用场景中,双因子轮动策略通过动态调整权重来适应市场变化。本文基于Python的backtrader框架,完整实现了ETF双因子轮动策略的量化回测系统,涵盖数据获取、因子计算到策略执行的完整开发流程,为量化投资爱好者提供了一套可复用的实战框架。

weixin_30254435的博客 358

用Python复现聚宽上的ETF动量轮动策略:从Slope因子到RSRS择时的保姆级教程

本文详细介绍了如何使用Python构建ETF动量轮动策略,结合Slope因子和RSRS择时系统实现量化交易。从数据准备、因子计算到信号生成和回测分析,提供完整的代码框架和优化技巧,帮助开发者高效复现聚宽上的策略,适用于量化交易实践和策略迁移。

weixin_42549496的博客 618

每天一道ACM(四)

本来今天想做喷水装置(二)的,发现对于现在的我来说有点难啊,还是再练练简单题吧,培养培养思路。 今天做南阳理工的一种排序。 一种排序: 描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复;还知道这个长方形的宽和长,编号、长、宽都是整数;现在要求按照一下方式排序(默认排序规则都是从小到大); 1.按照编号从小到大排序 2.对于编号相等的长方形,按照长方形的

tjuyangzhiyu的博客 705

动态长期主义:用三重纪律优化复利增长的股票策略

长期投资的本质不是时间长度,而是可持续的年化回报率(r)——复利公式FV=PV×(1+r)^t揭示了这一数学真相。当企业护城河坍塌、行业渗透率越过S曲线拐点或宏观约束根本迁移时,传统买入并持有策略易陷入‘长期套牢’。动态策略并非高频择时,而是以财务数据衰减曲线、行业生命周期理论和宏观适配矩阵为原理,通过时间纪律、数据纪律与替代纪律构筑决策防火墙,提升r的稳定性与可复制性。它适用于有5年以上经验、愿每年投入20小时系统复盘的中产投资者,在A股实证中显著跑赢纯被动组合。本文聚焦如何将这种‘动态长期主义’落地为可

weixin_30797199的博客 308

长方形去重排序

现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复;还知道这个长方形的宽和长,编号、长、宽都是整数;现在要求按照一下方式排序(默认排序规则都是从小到大)

Stay hungry, Stay foolish 758

量化价值投资新思路:成长股的动量效应分析

在投资的世界里,“价值"与"成长"似乎总是一对冤家:价值派投资者喜欢在打折时买入"好公司”,像在超市特价区淘优质商品;成长派则愿意为"潜力股"支付溢价,期待它们像小树苗长成参天大树。但现实中,很多投资者遇到过这样的困惑:买了看似便宜的价值股,却长期不涨;追了热门的成长股,又常常买在山顶。本文的目的,就是搭建一座连接"价值"与"成长"的桥梁——用量化的方法捕捉成长股中的动量效应。简单说,就是找到那些"既具有成长潜力(未来能长大),又处于上升趋势(正在加速滚雪球)"的股票。

2501_92132293的博客 1690

第四篇:关于python程序打包的问题-找不到fsspec

这个问题困扰了我将近两天的时间一直找不到什么好的办法,甚至打算放弃。主要原因是身边没有可以述说的人,也没有可以请教的人。正在想要放弃的时候找到了解决办法。 打包后运行程序是这样的, 大概意思是找不见fsspec这个依赖,刚接触python说实话对于这些第三方库理解不是很到位,我的理解就是:类似于java程序中的jar包,程序找不见了。可怎么让他找见了,刚开始以为我自己没有安装fsspec,在cmd中进行了安装,结果如下图所示 很明显,已经安装并且安装目录都有,跟着网上的一些解决办法,在打包的时候把这.

weixin_47861710的博客 5865

nyoj8 一种排序(STL 自定义结构体排序)

一种排序 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复;还知道这个长方形的宽和长,编号、长、宽都是整数;现在要求按照一下方式排序(默认排序规则都是从小到大);1.按照编号从小到大排序2.对于编号相等的长方形,按照长方形的长排序;3.如果编号和长都相同,按照长方形的宽排序;...

angtongyou1893的博客 695

AXI总线的Burst Type以及地址计算 | WRAP到底是怎么一回事?

AXI总线的transaction是burst-based的,因此有必要好好研究一下不同burst type的工作原理。此处略过burst的定义以及burst size、burst length等信号的介绍。

qiuzhongyu123的博客 2万+

ETF双因子轮动策略:动量与质量因子的Python实现与回测

量化投资中的因子选股策略通过特定指标筛选优质资产,其核心原理是基于市场异象构建投资组合。动量因子捕捉价格趋势持续性,质量因子评估风险调整后收益,两者结合能有效提升策略稳定性。在工程实践中,使用Python的pandas进行数据处理,akshare获取金融数据,backtrader构建回测框架,实现从数据获取、因子计算到权重分配的全流程。ETF双因子轮动策略通过动态调整宽基指数ETF持仓,在牛市捕捉趋势、震荡市控制回撤,为投资者提供系统化的资产配置方案。该策略结合行为金融学原理与程序化实现,适合作为量化入门到

weixin_33933118的博客 529

AppStore逆向分析:从网络抓包到自动化模拟的完整实践

在移动应用生态中,理解客户端与服务器之间的通信协议是进行自动化测试、数据分析和系统集成的关键技术基础。通过分析网络请求与响应,可以深入理解认证、会话管理和数据交换的原理,这对于构建稳定的自动化流程至关重要。其技术价值在于能够实现合法场景下的流程模拟,例如应用元数据监控、沙盒环境测试或内部工具开发。在实际应用场景中,开发者常需处理登录态维持、请求签名验证及风控策略应对等挑战。本文聚焦于AppStore这一封闭生态,详细拆解了其登录、查询等核心环节的通信机制,并探讨了使用Python结合抓包工具进行安全逆向分析

weixin_42524171的博客 929

Kubernetes集群资源优化实战:Volcano调度器如何帮你省下30%GPU算力

本文详细介绍了如何通过Volcano调度器的Binpack策略优化Kubernetes集群中的GPU资源利用率,解决AI模型训练中的资源碎片化问题。通过实战配置和调优指南,帮助用户提升30%的GPU算力利用率,显著降低任务等待时间和硬件成本。

weixin_30832143的博客 507

【python】做量化交易干货分享(附带无偿学习源码)

需要源码、资料、安装包、激活码戳这里拿:https://www.bilibili.com/opus/980926287955623941?国内量化交易的平台有几家,我个人比较喜欢用的是JoinQuant,里面有篇干货贴分享给大家,希望对各位有帮助。点击免费领取《优快云大礼包》:Python入门到进阶资料 & 实战源码 & 兼职接单方法 安全链接免费领取。6 Python数据分析基础教程:NumPy学习指南(第2版)

2401_85855266的博客 1446

SAP FICO 银企直连

银企直联或者自动付款的目的是和银行做一个接口,把SAP中的到期应付款(也包括预付款)按照一定格式(银行要求的)在审批后发送给银行,请银行按照这个付款指定进行付款,并跟踪付款状态的过程,这个过程在SAP中如何实现呢?根据个人项目经验,客户需求可分为如下三种: 1. 第一种是完全不自动方式,仅批量生成付款凭证,实际的付款还是通过原来的流程执行,和银行没有任何接口; 2. 第二种是半自动方式,这种方式下需要按照银行的要求的格式生成付款条件,然后把付款文件下载下来,通过企业版的网银接口把付款文件进行上载,提交后

IamRunjiang的博客 9291

【量化干货合集】你想要的,都在这里!

【量化干货合集】你想要的,都在这里!量化的春风吹拂下,我想,不管是在校的学霸学酥、炒股的程序猿哥哥, 还是股市沉浮多年正在寻找新的突破口的你,都值得拥有这样一份全面的资料。绝对的干货!(以下很多策略均包含源码分享供参考,欢迎大家多多交流谈论) 资料分享Python、研究报告、计量经济学、投资书籍、R语言等!(Book+Video)推荐一些Python入门学习资料(持续添加中…)Python编程【量化

shuigge的博客 5035

【TC397第23篇】深度解析TC397 EB MCAL开发系列:UART配置与POLL模式数据交互

通过本文,我们深度解析了TC397 EB MCAL开发系列中UART配置的POLL模式下的数据交互。从技术要点的介绍到实际案例的演示,希望读者能够更好地理解UART在POLL模式下的配置与应用。这不仅是对嵌入式系统开发的一次深刻探索,更是为项目提供了一种高效通信的解决方案。在未来的文章中,我们将继续深入研究嵌入式系统开发的各个方面,为广大开发者提供更多实用的技术知识。敬请期待,一同迎接嵌入式技术的新篇章!

一直在水些技术小文 470

深入探讨 SAP ERP 物料主数据中的 Valuation Type

在 SAP ERP 系统中,是用于区分同一种物料在不同条件下的估价方法。物料的估价可以因产地、质量等级、供应商或批次的不同而有所差异。通过为物料设置不同的估价类别,使企业能够对这些差异进行有效管理。为了实现更细致的物料成本核算,SAP 系统通过(分批估价)功能允许为同一物料设置多个估价类型。这种方法特别适合那些在来源、质量、或其他参数上存在显著差异的物料。是 SAP ERP 和 SAP S/4HANA 中物料主数据的核心组成部分,为企业提供了灵活的成本管理工具。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1408

一种排序

描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复;还知道这个长方形的宽和长,编号、长、宽都是整数;现在要求按照一下方式排序(默认排序规则都是从小到大); 1.按照编号从小到大排序 2.对于编号相等的长方形,按照长方形的长排序; 3.如果编号和长都相同,按照长方形的宽排序; 4.如果编号、长、宽都相同,就只保留一个长方形用于排序,删除多余的长方形;最后排好序按照指定格式显...

开始的地方 281

mongodb在游戏开发领域的优势

目前游戏服务器使用mysql作为数据库的较多,然而,使用mongodb来作为存储层,在某些方面比mysql更为方便和适合。

littleschemer的博客 1700

STL-set

题目描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复;还知道这个长方形的宽和长,编号、长、宽都是整数;现在要求按照一下方式排序(默认排序规则都是从小到大); 1.按照编号从小到大排序 2.对于编号相等的长方形,按照长方形的长排序; 3.如果编号和长都相同,按照长方形的宽排序; 4.如果编号、长、宽都相同,就只保留一个长方形用于排序,删除多余的长方形;最后

xiaoyao_zhang的博客 243

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

上一篇: BQ76952芯片深度解析:从供电、ADC到硬件保护,打造高可靠BMS设计
下一篇: 模板驱动型文档自动化:让标准化报告一键生成
com_xpp
博客等级 码龄16年 23粉丝 160原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值