Warning: file_exists(): open_basedir restriction in effect. File(/www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/wp-content/db.php) is not within the allowed path(s): (/www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/:/tmp/:/proc/:/var/log/nginx/:/www/wwwroot/com.xiximiao.oa/com.cmstop/public/:/www/wwwroot/com.xiximiao.oa/com.cmstop/vendor/:/www/wwwroot/com.xiximiao.oa/com.cmstop/ppk/) in /www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/wp-includes/load.php on line 707
2312 机器学习多因子,50只持仓,14年37倍.py » 轻知量化 QMT、PTrade、聚宽策略分享交流平台

2312 机器学习多因子,50只持仓,14年37倍.py

# 风险及免责提示:该策略由聚宽用户在聚宽社区分享,仅供学习交流使用。
# 标题:致敬聚宽: 机器学习多因子,50只持仓,14年37倍
# 作者:Gyro^.^

# 克隆自聚宽文章:https://www.joinquant.com/post/10778
# 标题:【量化课堂】机器学习多因子策略
# 作者:JoinQuant量化课堂

# 回测资金需要 12345678

import pandas as pd          # 将 pandas库导入当前环境,并给它指定一个别名 pd
import numpy as np
import datetime as dt
from sklearn.svm import SVR
from jqdata import *

def initialize(context):
    log.set_level('order', 'error')        # 设置日志级别,过滤order和error级别的日志
    set_option('use_real_price', True)     # 用真实价格交易
    set_option('avoid_future_data', True)  # 打开防未来函数

    run_daily(handle_training, 'before_open')  # 每天开盘前运行handle_training函数
    run_daily(handle_trader, 'open')           # 每天开盘时运行handle_trader函数

def handle_trader(context):
    # 初始化变量
    choice = g.choice  # 从全局变量g获取选择的股票列表
    psize  = g.psize   # 从全局变量g获取每只股票的买入金额
    cdata  = get_current_data()  # 获取当前行情数据
    # 卖出逻辑
    for s in context.portfolio.positions:            # 遍历当前持仓的股票
        if s not in choice and not cdata[s].paused:  # 如果股票不在列表中并且股票没有停牌
            log.info('sell', s, cdata[s].name)  # 记录卖出信息
            order_target(s, 0, LimitOrderStyle(cdata[s].last_price))  # 下单将股票卖出到0
    # 买入逻辑
    for s in choice:  # 遍历choice中的股票
        if context.portfolio.available_cash < psize:  # 如果可用现金小于设定的买入金额
            break  # 停止买入
        if s not in context.portfolio.positions and not cdata[s].paused:  # 如果当前持仓中没有该股票并且股票没有停牌
            log.info('buy', s, cdata[s].name)  # 记录买入信息
            order_value(s, psize, LimitOrderStyle(cdata[s].last_price))  # 下股票限价单买入股票

def handle_training(context):
    # 参数设置
    n_position = 50  # 设置持仓股票数量
    n_choice = int(1.2*n_position)  # 设置选股数量,为持仓数量的120%
    index = '399317.XSHE'  # 设置市场指数代码 国证A指
    cdata  = get_current_data()  # 获取当前数据
    dt_last = context.previous_date  # 获取上个交易日日期
    # 股票池
    stocks = get_index_stocks(index, dt_last)  # 获取市场指数的成分股
    # 获取股票的基本面财务数据
    q = query(
            valuation.code,        # 股票代码
            valuation.market_cap,  # 总市值
            balance.total_assets - balance.total_liability,   # 总资产减去总负债,即净资产
            income.net_profit,     # 净利润
            balance.development_expenditure,                  # 开发支出
            valuation.pe_ratio,    # 市盈率
            balance.total_assets / balance.total_liability,   # 总资产/总负债
            indicator.inc_revenue_year_on_year / 100,         # 营业收入同比增长率,除以100转换为小数形式
        ).filter(                  # 过滤条件
            valuation.code.in_(stocks),                       # 只选择股票代码在之前定义的stocks列表中的数据
            balance.total_assets > balance.total_liability,   # 过滤出那些总资产大于总负债的公司,即净资产为正的公司
            income.net_profit > 0,                            # 过滤出那些净利润大于0的公司,即盈利的公司
        )
    # 处理数据
    df = get_fundamentals(q, dt_last).fillna(0).set_index('code')  # 获取数据并设置索引
    df.columns = ['log_mc', 'log_NC', 'log_NI', 'log_RD', 'PE', 'lev', 'grow']  # 设置列名
    # 自定义函数,用于处理数据
    def _sign_ln(X):  # 定义函数,用于计算带符号的自然对数
        return sign(X) * np.log(1.0 + abs(X))
    # 应用自定义函数处理数据
    df['log_mc'] = _sign_ln(df['log_mc'])
    df['log_NC'] = _sign_ln(df['log_NC'])
    df['log_NI'] = _sign_ln(df['log_NI'])
    df['log_RD'] = _sign_ln(df['log_RD'])
    df['PE'] = _sign_ln(df['PE'])
    df['lev'] = _sign_ln(df['lev'])
    df['grow'] = _sign_ln(df['grow'])
    # 行业因子
    industry_list = get_industries('sw_l1', dt_last).index.tolist()  # 获取一级行业列表,并把这个列表转换成python列表格式。
    for sector in industry_list:  # 遍历行业
        istocks = get_industry_stocks(sector, dt_last)  # 获取行业成分股
        s = pd.Series(0, index=df.index)  # 创建0值序列
        s[set(istocks) & set(df.index)] = 1  # 将行业成分股标记为1
        df[sector] = s  # 添加到DataFrame
    # 支持向量回归模型
    svr = SVR(kernel='rbf')  # 创建SVR模型
    # 训练模型
    Y = df['log_mc']  # 目标变量
    X = df.drop('log_mc', axis=1)  # 特征变量
    model = svr.fit(X, Y)  # 训练模型
    # 选择股票
    r = Y - pd.Series(svr.predict(X), Y.index)  # 计算残差
    r = r[r < 0].sort_values().head(n_choice)  # 选择负残差最大的n_choice只股票
    choice = r.index.tolist()  # 将选择的股票代码存储到列表
    # 记录待卖出和待买入的股票
    for s in context.portfolio.positions:  # 遍历当前持仓
        if s not in choice:  # 如果不在choice列表中
            log.info('to sell', s, cdata[s].name)  # 记录卖出信息
    for s in choice:  # 遍历choice列表
        if s not in context.portfolio.positions:  # 如果不在当前持仓中
            log.info('to buy', s, cdata[s].name)  # 记录买入信息
    # 保存结果到全局变量
    g.choice = choice  # 保存选择的股票列表
    g.psize = 1.0/n_position * context.portfolio.total_value  # 保存每只股票的买入金额
# end
2025-02-21
⚠️
本站资源大多来自网络,仅供网友学习交流,未经作者或上传书面授权,请勿作他用。
站长 vx: xiangyin615 或者 留言反馈 ,我们将尽快处理。
Notice: When you of the legal rights be violate, please stir to vx: xiangyin615
个人中心
购物车
优惠劵
搜索