PyTorch量化技术教程:第四章 PyTorch在量化交易中的应用

PyTorch量化技术教程:PyTorch基础入门

本教程旨在为读者提供一套全面且深入的PyTorch技术在量化交易领域应用的知识体系。系统涵盖PyTorch基础入门、核心组件详解、模型构建与训练,以及在A股市场中的实战应用。采用理论与实战深度融合的讲解模式,详细剖析如何运用PyTorch打造量化交易系统全流程。从数据处理的精细操作,到模型训练的优化技巧,再到交易信号生成的精准逻辑,以及风险管理的严谨策略,每个环节都通过专业示例和代码实现进行阐释,确保读者能够扎实掌握并灵活运用所学知识。
文中内容仅限技术学习与代码实践参考,市场存在不确定性,技术分析需谨慎验证,不构成任何投资建议。适合量化新手建立系统认知,为策略开发打下基础。


目录

  1. PyTorch基础入门

    • 1.1 PyTorch简介与环境搭建
    • 1.2 Tensor基础操作与自动求导机制
  2. PyTorch核心组件详解

    • 2.1 nn.Module模块使用与自定义
    • 2.2 优化器选择与使用
    • 2.3 数据加载与预处理
  3. PyTorch模型构建与训练

    • 3.1 神经网络模型构建流程
    • 3.2 模型训练技巧与实践
    • 3.3 模型评估与保存加载
  4. PyTorch在量化交易中的应用

    • 4.1 时间序列分析与预测
    • 4.2 量化交易策略构建与优化
    • 4.3 风险管理与绩效评估
  5. 综合实战项目

    • 5.1 基于A股市场的量化交易系统开发
    • 5.2 模型部署与实际交易模拟

第四章 PyTorch在量化交易中的应用

4.1 时间序列分析与预测

时间序列分析基础

时间序列分析是量化交易中的重要环节,它通过对历史数据的分析来预测未来的价格走势。常用的时间序列模型包括ARIMA、LSTM等。在PyTorch中,可以使用循环神经网络(RNN)及其变体如长短期记忆网络(LSTM)和门控循环单元(GRU)来处理时间序列数据。

使用LSTM进行时间序列预测

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import pandas as pd
import talib


# 定义时间序列数据集类
class TimeSeriesDataset(Dataset):
    def __init__(self, file_path, sequence_length=10):
        self.data = pd.read_parquet(file_path)
        # 计算技术指标
        self.data["MA5"] = talib.MA(self.data["close"], timeperiod=5)
        self.data["MA10"] = talib.MA(self.data["close"], timeperiod=10)
        self.data["RSI"] = talib.RSI(self.data["close"], timeperiod=14)
        self.data["MACD"], _, _ = talib.MACD(
            self.data["close"], fastperiod=12, slowperiod=26, signalperiod=9
        )
        # 数据清洗
        self.data.dropna(inplace=True)
        # 特征选择
        self.features = self.data[["open", "high", "low", "MA5", "MA10", "RSI", "MACD"]]
        self.labels = self.data[["close"]]
        # 归一化
        self.scaler_features = StandardScaler()
        self.scaler_labels = StandardScaler()
        self.features_scaled = self.scaler_features.fit_transform(self.features)
        self.labels_scaled = self.scaler_labels.fit_transform(self.labels)
        # 创建序列数据
        self.sequence_length = sequence_length
        self.sequences = []
        self.targets = []
        for i in range(len(self.features_scaled) - sequence_length):
            self.sequences.append(self.features_scaled[i : i + sequence_length])
            self.targets.append(self.labels_scaled[i + sequence_length])

    def __len__(self):
        return len(self.targets)

    def __getitem__(self, idx):
        sequence = torch.tensor(self.sequences[idx], dtype=torch.float32)
        target = torch.tensor(self.targets[idx], dtype=torch.float32)
        return sequence, target


# 定义LSTM模型
class LSTMModel(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, num_layers):
        super(LSTMModel, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).requires_grad_()
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).requires_grad_()
        out, (hn, cn) = self.lstm(x, (h0.detach(), c0.detach()))
        out = self.fc(out[:, -1, :])
        return out


# 创建数据集和数据加载器
sequence_length = 10
dataset = TimeSeriesDataset(
    "./data/ashare_data.parquet", sequence_length=sequence_length
)
train_size = int(0.8 * len(dataset))
test_size = len(dataset) - train_size
train_dataset, test_dataset = torch.utils.data.random_split(
    dataset, [train_size, test_size]
)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

# 定义模型、损失函数和优化器
input_size = dataset.features.shape[1]
hidden_size = 64
output_size = 1
num_layers = 2
model = LSTMModel(input_size, hidden_size, output_size, num_layers)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
    model.train()
    for sequences, targets in train_loader:
        outputs = model(sequences)
        loss = criterion(outputs, targets)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    if (epoch + 1) % 10 == 0:
        model.eval()
        with torch.no_grad():
            total_loss = 0
            for sequences, targets in test_loader:
                outputs = model(sequences)
                total_loss += criterion(outputs, targets).item()
            avg_loss = total_loss / len(test_loader)
            print(f"Epoch [{epoch+1}/{num_epochs}], Test Loss: {avg_loss:.4f}")

# 保存模型
torch.save(model.state_dict(), "./models/lstm_model.pth")

输出

text 复制代码
Epoch [10/100], Test Loss: 0.0102
Epoch [20/100], Test Loss: 0.0111
Epoch [30/100], Test Loss: 0.0049
Epoch [40/100], Test Loss: 0.0029
Epoch [50/100], Test Loss: 0.0022
Epoch [60/100], Test Loss: 0.0019
Epoch [70/100], Test Loss: 0.0023
Epoch [80/100], Test Loss: 0.0019
Epoch [90/100], Test Loss: 0.0022
Epoch [100/100], Test Loss: 0.0024

在这个示例中,我们使用LSTM模型对A股的时间序列数据进行预测。LSTM能够有效地捕捉时间序列中的长期依赖关系,适用于股票价格等具有时间依赖性的数据。

4.2 量化交易策略构建与优化

量化交易策略基础

量化交易策略是基于数学模型和统计分析来指导交易决策的方法。常见的量化交易策略包括均值回归、动量策略、套利策略等。在PyTorch中,可以构建复杂的模型来生成交易信号。

基于PyTorch的量化交易策略构建

python 复制代码
import numpy as np


# 定义交易策略类
class TradingStrategy:

    def __init__(self, model_path, scaler_features, scaler_labels, sequence_length):
        self.model = LSTMModel(input_size, hidden_size, output_size, num_layers)
        self.model.load_state_dict(torch.load(model_path))
        self.model.eval()
        self.scaler_features = scaler_features
        self.scaler_labels = scaler_labels
        self.sequence_length = sequence_length

    def generate_signals(self, new_data):
        # 数据预处理
        new_data["MA5"] = talib.MA(new_data["close"], timeperiod=5)
        new_data["MA10"] = talib.MA(new_data["close"], timeperiod=10)
        new_data["RSI"] = talib.RSI(new_data["close"], timeperiod=14)
        new_data["MACD"], _, _ = talib.MACD(
            new_data["close"], fastperiod=12, slowperiod=26, signalperiod=9
        )
        new_data.dropna(inplace=True)
        features = new_data[["open", "high", "low", "MA5", "MA10", "RSI", "MACD"]]
        features_scaled = self.scaler_features.transform(features)
        sequences = []
        for i in range(len(features_scaled) - self.sequence_length):
            sequences.append(features_scaled[i : i + self.sequence_length])
        sequences_tensor = torch.tensor(np.array(sequences), dtype=torch.float32)

        # 生成预测
        with torch.no_grad():
            predictions = self.model(sequences_tensor)
        predictions_rescaled = self.scaler_labels.inverse_transform(predictions.numpy())

        # 生成交易信号
        signals = []
        for i in range(len(predictions_rescaled)):
            if (
                predictions_rescaled[i]
                > new_data["close"].values[i + self.sequence_length]
            ):
                signals.append(1)  # 买入信号
            else:
                signals.append(0)  # 卖出信号
        return signals


# 使用示例
strategy = TradingStrategy(
    "./models/lstm_model.pth",
    dataset.scaler_features,
    dataset.scaler_labels,
    sequence_length,
)
new_data = pd.read_parquet("./data/ashare_data.parquet")
signals = strategy.generate_signals(new_data)
print(signals)

输出

text 复制代码
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1]

在这个示例中,我们构建了一个基于LSTM模型的量化交易策略,通过模型预测未来的价格走势来生成交易信号。

策略优化与回测

python 复制代码
# 定义回测函数
def backtest(strategy, historical_data):
    # 数据预处理
    historical_data["MA5"] = talib.MA(historical_data["close"], timeperiod=5)
    historical_data["MA10"] = talib.MA(historical_data["close"], timeperiod=10)
    historical_data["RSI"] = talib.RSI(historical_data["close"], timeperiod=14)
    historical_data["MACD"], _, _ = talib.MACD(
        historical_data["close"], fastperiod=12, slowperiod=26, signalperiod=9
    )
    historical_data.dropna(inplace=True)
    features = historical_data[["open", "high", "low", "MA5", "MA10", "RSI", "MACD"]]
    labels = historical_data[["close"]]
    features_scaled = strategy.scaler_features.transform(features)
    labels_scaled = strategy.scaler_labels.transform(labels)
    sequences = []
    targets = []
    for i in range(len(features_scaled) - sequence_length):
        sequences.append(features_scaled[i : i + sequence_length])
        targets.append(labels_scaled[i + sequence_length])
    sequences_tensor = torch.tensor(sequences, dtype=torch.float32)
    targets_tensor = torch.tensor(targets, dtype=torch.float32)

    # 生成预测并计算收益
    with torch.no_grad():
        predictions = strategy.model(sequences_tensor)
    predictions_rescaled = strategy.scaler_labels.inverse_transform(predictions.numpy())
    returns = []
    for i in range(1, len(predictions_rescaled)):
        if (
            predictions_rescaled[i - 1]
            > historical_data["close"].values[i + sequence_length - 1]
        ):
            # 买入并持有
            returns.append(
                (
                    historical_data["close"].values[i + sequence_length]
                    - historical_data["close"].values[i + sequence_length - 1]
                )
                / historical_data["close"].values[i + sequence_length - 1]
            )
        else:
            # 卖出并持有现金
            returns.append(0)
    cumulative_return = np.prod(1 + np.array(returns)) - 1
    return cumulative_return


# 进行回测
historical_data = pd.read_parquet("./data/ashare_data.parquet")
cumulative_return = backtest(strategy, historical_data)
print(f"累计收益率: {cumulative_return:.4f}")

输出

text 复制代码
累计收益率: 0.5352

在这个示例中,我们对构建的量化交易策略进行回测,计算其在历史数据上的累计收益率,以评估策略的有效性。

4.3 风险管理与绩效评估

风险管理基础

风险管理是量化交易中的重要环节,旨在控制交易中的潜在损失。常用的风险管理方法包括止损、止盈、仓位管理等。

绩效评估指标

在量化交易中,常用的绩效评估指标包括夏普比率、最大回撤、累计收益率等。

python 复制代码
# 计算夏普比率
def sharpe_ratio(returns, risk_free_rate=0):
    mean_return = np.mean(returns)
    std_return = np.std(returns)
    sharpe = (mean_return - risk_free_rate) / std_return
    return sharpe


# 计算最大回撤
def max_drawdown(cumulative_returns):
    peak = cumulative_returns[0]
    max_dd = 0
    for ret in cumulative_returns:
        if ret > peak:
            peak = ret
        dd = (peak - ret) / peak
        if dd > max_dd:
            max_dd = dd
    return max_dd


# 使用示例
returns = [0.01, -0.02, 0.03, 0.02, -0.01]
sharpe = sharpe_ratio(returns)
max_dd = max_drawdown(np.cumprod(1 + np.array(returns)))
print(f"夏普比率: {sharpe:.4f}")
print(f"最大回撤: {max_dd:.4f}")

输出

text 复制代码
夏普比率: 0.3235
最大回撤: 0.0200

实战示例:综合风险管理与绩效评估

python 复制代码
# 定义风险管理类
class RiskManagement:
    def __init__(self, max_drawdown_threshold=0.1, stop_loss=0.05, take_profit=0.1):
        self.max_drawdown_threshold = max_drawdown_threshold
        self.stop_loss = stop_loss
        self.take_profit = take_profit

    def monitor_risk(self, cumulative_returns):
        if not cumulative_returns:  # 如果累计收益率为空,返回 True
            return True
        current_dd = self.max_drawdown(cumulative_returns)
        if current_dd > self.max_drawdown_threshold:
            return False  # 风险过高,停止交易
        return True

    def max_drawdown(self, cumulative_returns):
        # 计算最大回撤
        peaks = []
        peak = cumulative_returns[0] if len(cumulative_returns) > 0 else 0
        for ret in cumulative_returns:
            if ret > peak:
                peak = ret
            peaks.append(peak)
        # 避免除以零的情况
        drawdowns = []
        for peak_val, ret in zip(peaks, cumulative_returns):
            if peak_val == 0:
                drawdowns.append(0.0)
            else:
                drawdowns.append((peak_val - ret) / peak_val)
        max_dd = max(drawdowns, default=0)
        return max_dd

    def execute_trade(self, signal, current_price, position):
        if signal == 1:  # 买入信号
            if position is None:
                position = current_price
            else:
                # 检查是否达到止损或止盈条件
                pnl = (current_price - position) / position
                if pnl <= -self.stop_loss:
                    position = None  # 止损
                elif pnl >= self.take_profit:
                    position = None  # 止盈
        else:  # 卖出信号
            position = None
        return position


# 使用示例
risk_manager = RiskManagement()
position = None
for i in range(len(signals)):
    signal = signals[i]
    current_price = new_data["close"].values[i + sequence_length]
    position = risk_manager.execute_trade(signal, current_price, position)
    # 检查风险
    if i + 1 >= sequence_length:
        cumulative_returns = [
            (
                new_data["close"].values[j + sequence_length]
                - new_data["close"].values[sequence_length]
            )
            / new_data["close"].values[sequence_length]
            for j in range(i + 1)
        ]
        if not risk_manager.monitor_risk(cumulative_returns):
            print("风险过高,停止交易")
            break

输出

text 复制代码
风险过高,停止交易

在这个实战示例中,我们展示了如何在量化交易中进行风险管理和绩效评估,确保交易策略在实际应用中的稳定性和有效性。

风险提示与免责声明

本文内容基于公开信息研究整理,不构成任何形式的投资建议。历史表现不应作为未来收益保证,市场存在不可预见的波动风险。投资者需结合自身财务状况及风险承受能力独立决策,并自行承担交易结果。作者及发布方不对任何依据本文操作导致的损失承担法律责任。市场有风险,投资须谨慎。

相关推荐
蹦蹦跳跳真可爱5892 分钟前
Python----机器学习(基于PyTorch的线性回归)
人工智能·pytorch·python·机器学习·线性回归
Json_8 分钟前
Vue 构造器 Vue.extend
前端·vue.js·深度学习
Json_16 分钟前
Vue 实例方法
前端·vue.js·深度学习
搞不懂语言的程序员26 分钟前
装饰器模式详解
开发语言·python·装饰器模式
mosquito_lover130 分钟前
矿山边坡监测预警系统设计
人工智能·python·深度学习·神经网络·视觉检测
船长@Quant31 分钟前
PyTorch量化进阶教程:第二章 Transformer 理论详解
pytorch·python·深度学习·transformer·量化交易·sklearn·ta-lib
Json_44 分钟前
实例入门 实例属性
前端·深度学习
Json_44 分钟前
JS中的apply和arguments小练习
前端·javascript·深度学习
攻城狮7号1 小时前
【第一节】Python爬虫基础-HTTP基本原理
爬虫·python·python爬虫
Json_1 小时前
Vue Methods Option 方法选项
前端·vue.js·深度学习