DrPepper8888 / IPMN

0 stars 0 forks source link

1 #23

Open DrPepper8888 opened 7 months ago

DrPepper8888 commented 7 months ago
import pandas as pd

# 交易假设
INITIAL_CAPITAL = 100000  # 初始资金为 100,000 美元
FEE_RATE = 0.03 / 100  # 交易费用为0.03%
TAX_RATE = 0.1 / 100  # 税率为净收入的0.1%

# 假设数据已加载并处理成如下形式的DataFrame
# pivot_df 行索引是trans_date,列索引是ticker,值value为num,num的正负代表buy/sell
# trans_df 第一列是trans_date,第二列是ticker,第三列是num,num的正负代表buy/sell,第四列是当天该ticker的adj_price,第五列是该交易的profit(正就是赚钱了,负是cost或者亏钱),第六列是当前现金cash
# holding_df 行索引是trans_date,列索引是ticker,值value为num,num的正负代表buy/sell
# price_df 行索引是trans_date,列索引是ticker,值value为adj_price

def calculate_profit(ticker, num, adj_close, fee_rate=FEE_RATE):
    """计算交易利润"""
    profit = num * adj_close * (1 - fee_rate) if num > 0 else num * adj_close * (1 + fee_rate)
    return profit

def adjust_holding(holding_df, ticker, num, adj_close, date):
    """调整持仓记录"""
    holding_df.loc[date, ticker] += num

def execute_trade(cash, ticker, num, adj_close, date, holding_df, trans_df):
    """执行交易"""
    profit = calculate_profit(ticker, num, adj_close)
    cash += profit
    adjust_holding(holding_df, ticker, num, adj_close, date)
    trans_df = trans_df.append({
        'trans_date': date,
        'ticker': ticker,
        'num': num,
        'adj_price': adj_close,
        'profit': profit,
        'cash': cash
    }, ignore_index=True)
    return cash, trans_df

def process_trading_day(date, pivot_df, price_df, holding_df, cash, trans_df, initial_capital):
    """
    处理单个交易日:跨天调仓+止损判断,每天先进行资金回收

    参数:
    date (pd.Timestamp): 当前交易日期
    pivot_df (pd.DataFrame): 内幕交易数据面板,行索引是trans_date,列索引是ticker,值value为num,num的正负代表buy/sell
    price_df (pd.DataFrame): 每日收盘价数据,其中索引为日期,列名为股票代码
    holding_df (pd.DataFrame): 当前持仓数据,其中索引为日期,列名为股票代码,值表示持有数量
    cash (float): 当前现金余额
    trans_df (pd.DataFrame): 交易记录数据框,用于记录每次交易详情。第一列是trans_date,第二列是ticker,第三列是num,num的正负代表buy/sell,第四列是当天该ticker的adj_price,第五列是该交易的profit(正就是赚钱了,负是cost或者亏钱),第六列是当前现金cash
    initial_capital (float): 初始投资本金

    返回:
    cash (float): 更新后的现金余额
    trans_df (pd.DataFrame): 更新后的交易记录数据框
    """

    # 止损判断,如果亏了5%或持仓超过30天,则卖出全部股票
    for trans_date, ticker in holding_df.index:
        num = holding_df.loc[trans_date, ticker]

        if num > 0:
            current_price = price_df.loc[date, ticker]
            threshold_price = price_df.loc[trans_date, ticker] * 0.95
            holding_duration = (date - trans_date).days

            if current_price < threshold_price or holding_duration > 30:
                cash, trans_df = execute_trade(cash, ticker, -num, current_price, date, holding_df, trans_df)

    # 跨天跳仓,实现部分收益条件下的卖出策略
    for ticker, num in holding_df.loc[date].items():
        current_price = price_df.loc[date, ticker]
        threshold_price = price_df.loc[trans_date, ticker]

        if num > 0:
            # 已持有的股票收益率达到2%,则卖出一半股票收回资金
            #TODO:2%-4%
            if current_price * num  - threshold_price * num * 1.02  > 0:
                sell_num = num / 2
                cash, trans_df = execute_trade(cash, ticker, -sell_num, current_price, date, holding_df, trans_df)

            # 股票收益率达到4%,则出售所有股票以收回资金
            elif current_price * num - threshold_price * num * 1.04 > 0:
                cash, trans_df = execute_trade(cash, ticker, -num, current_price, date, holding_df, trans_df)

    # 进入当天交易
    day_pivot = pivot_df.loc[date]
    today_data = price_df.loc[date]

    if day_pivot.nunique() == 1:
        # 当天只有一个ticker有交易,直接处理
        ticker = day_pivot.index[0]
        num = day_pivot[ticker]
        adj_close = price_df.loc[date, ticker]

        if num > 0:
            # Buy.TODO:分配70%的cash买
            # 使用0.7的现金购买,不用反复记录cash,直接拨了70%现金去买
            cash = 0.3 * cash
            buy_num = 0.7 * cash / adj_close
            _, trans_df = execute_trade(cash, ticker, buy_num, adj_close, date, holding_df, trans_df)

        else if num<0 :
            # Sell
            # TODO: 实现卖出逻辑,包括长期内幕卖出和短期内幕卖出
            # holding_time()
            #(判断长短期)
            #长期内幕卖出函数:遵循内幕交易的卖出,在当前日直接卖出。
            #短期内幕卖出函数:先判断该卖出交易日是对应买入的第几个卖出交易日
                #如果第一个内幕交易卖出当日回报达到4%直接卖出,当日未达到,就先不卖出
                #如果当前是第二个内幕交易日,如果当天收益率达到3%就卖出,未达到就不卖出
                #如果当前是第三个内幕交易日or距离买入时间到第15天,全部抛出

    else:
    # 当天num值不为零的ticker有好几个,当日资金分配
  # 当天num值不为零的ticker有好几个,当日资金分配
    if len(today_data[today_data != 0]) > 1:

        # 对当天所有有交易的stock进行购买,按照公司当天adj close*num的权重,分配0.7*cash;
        day_pivot = pivot_df.loc[date]
        trading_stocks = day_pivot.index[day_pivot.abs() > 0]
        trade_values = today_data.loc[trading_stocks] * day_pivot[trading_stocks].abs()
        weights = trade_values / trade_values.sum()
        allocated_funds = {stock: 0.7 * cash * weight for stock, weight in weights.items()}

        # 使用execute_trade()函数执行交易、更新现金余额、持仓和交易记录
        for stock, amount in allocated_funds.items():
            cash, trans_df = execute_trade(cash, stock, amount, today_data[stock], date, holding_df, trans_df)

    # 返回更新后的现金余额、持仓数据和交易记录数据框
    return cash, holding_df, trans_df

# 按pivot_df的trans_date列进行循环
trans_dates = pivot_df.index.unique()
for date in trans_dates:
    cash, holding_df, trans_df = process_trading_day(date, pivot_df, price_df, holding_df, cash, trans_df, INITIAL_CAPITAL)

# 最终输出结果
print("Cash at the end:", cash)
print("Final Holding DF:")
print(holding_df)
print("Final Trans DF:")
print(trans_df)