Backtrader 文档学习- 整体架构功能分析理解

news2024/9/21 0:49:35

Backtrader 文档学习- 架构功能分析理解

1. 概述

backtrader是一个用于开发和执行交易策略的Python框架。它提供了一套完整的工具和功能,使得用户可以方便地进行策略回测、实盘交易以及数据分析。

backtrader的入口为Cerebro类,该类将所有输入(Data Feeds)、策略 (Strategy)、观察者(Observers)、策略评估(Analyzers) 、经纪人(Broker)、订单(Order)、交易(Trade)和日志记录(Writers)整合起来,实现回测以及交易,并返回结果和图表。

backtrader优缺点,先说缺点:

(1)缺点:
  • 在于使用元类编程技术,使用了大量的类,调试的时候会比较难。
  • 对于python的要求高,需要掌握pandas,matplotlib ,有基础上手更容易。
  • 对环境存在兼容性, 使用pandas ,numpy ,matplotlib 的版本不能太高。
  • 对回测结果分析,需定制化做大量工作,比如需要将各类策略的测试结果,除了能打印日志外,需要保存到数据库中,便于后期对比分析,比如周期参数,5天、10天、20天同一个策略不同的周期,执行的绩效记录处理。
(2)优点:
  • 功能非常完善,支持多品种、多策略、多周期的回测和交易,编写策略简单,上手容易。
  • 交易的品种非常丰富(股票、期货、期权、外汇等)。
  • 详细的文档,提供的用例比较多,可以学习和根据需求改进 。
  • 在量化框架上,收费的居多,优矿,米筐,聚宽,不能本地化部署。免费开源的少。
  • 支持内部方法的重写,可以方便定制化策略。
  • 内置多个指标参数,很丰富,包括Talib 。
(3)使用目标:
  • 以研究策略为主,验证策略效果,选择标的股票。
  • 不需要太多的参数因子,基于通用指标,可以灵活组合。
  • 不做实盘高频交易。
  • 适合个人学习使用,探索基本量化方向,避免盲目交易,有数据支撑。

2.架构理解

backtrader的整体架构可以分为以下主要组件:
在这里插入图片描述

(1)数据源(Data Feeds):

backtrader支持多种数据源,包括CSV文件、Pandas DataFrame、实时数据源等。用户可以根据自己的需求选择适合的数据源,并通过数据加载器将数据加载到backtrader中进行处理。
backtrader回测的数据类型是由一系列的点组成的Lines,通常包括以下类别的数据:Open(开盘价)、High(最高价)、Low(最低价)、 Close(收盘价)、Volume(成交量)、OpenInterest(未平仓权益)。Data Feeds(数据加载)、Indicators(技术指标)和Strategies(策略)都会生成 Lines。价格数据中的所有的开盘价按时间组成一条 Line,因此一组含有以上6个类别的价格数据,共有6条 Lines。如果算上DateTime(时间,可以看作是一组数据的主键),一共有7条 Lines。Lines根据需要是可以扩展的。

核心概念:
Line的概念和Python中的list索引不同,Python List中索引-1,表示最后一个数据。
一条Line数据的下标为0表示访问当前时刻数据,-1表示访问下一个数据。在回测过程中,无需知道已经处理了多少条/分钟/天/月,”0”一直指向当前值,下标 -1 来访问下一个值,下标 -2 访问下下一个值。
在backtrader中,-1指的是当前处理数据(索引为0)的上一个数据。
Lines是随时变化的,run的时候,next不断改变Lines的长度,在数据载入,策略,指示器应用中,需要测量Lines的长度。
两个长度函数:len和buflen之间的区别:

  • len已处理了Lines
  • buflen为数据加载Lines的总数
(2)策略(Strategies):

backtrader提供了一个基类Strategy,用户可以继承该类并实现自己的交易策略。策略类中定义了一系列的回调函数,用户可以在回测函数中编写具体的交易逻辑。

该模块是回测系统最核心的部分,需要设计交易决策,得出买入/卖出信号。策略类代码包含重要的参数和用于执行策略的功能,要定义的参数或函数名如下:
(1)params:全局参数,可选,用于更改交易策略中变量/参数的值,可用于参数调优。
(2)log:日志,可选,用于记录策略的执行日志,可以打印出该函数提供的日期时间和txt变量。
(3)init:用于初始化交易策略,类中使用的全局变量定义,在其中声明的任何指标都会在next()方法调用之前进行计算。部分python操作符不支持,需要使用bt内置函数来处理,例如bt.And, bt.Or, bt.All, bt.Any等。
(4)notify_order,可选,用于跟踪交易订单(order)的状态。order具有提交,接受,买入/卖出执行和价格,已取消/拒绝等状态。
(5)notify_trade,可选,用于跟踪交易的状态,任何已平仓的交易都将报告毛利和净利润。
(6)next,必选,用于制定交易策略的函数,策略模块最核心的部分。
当满足所有data/indicators的最小周期后,执行将对所有剩余数据点调用。
如period是10 ,最小周期达到后,开始执行next方法。
(7)nextstart(),可选,方法执行一次,在最小周期的data/indicators满足时,默认执行next方法。
如period是10 ,在到达9执行最小周期达到后,执行一次nextstart,之后执行next方法。
(8)prenext(),可选,方法将在所有数据/指标的最小周期满足策略开始执行之前调用执行。
如period是10 ,在1到9执行最小周期之间,执行prenext。
(9)start(),可选,在回测即将开始之前调用,执行一次。
(10)stop(),可选,在回测即将结束之前调用,执行一次。
(11)notify_cashvalue(),可选,接收当前使用的资金余额
(12)notify_fund(),可选,策略的资金和价值发生变化时被调用。用于跟踪和记录策略的现金、价值、基金价值和持仓股票的数量。

(3)指标(Indicators):

backtrader内置了许多常用的技术指标,如移动平均线、MACD、RSI等。用户可以通过指标类来计算这些指标,并在策略中使用。
backtrader在指标中也集成了TA-Lib库

(4)订单(Order):

backtrader提供了一套完善的订单管理系统,用户可以通过创建订单对象来执行买入和卖出操作。订单管理系统还支持订单状态的跟踪和管理。
将策略中逻辑做出的决策转换为适合经纪人执行操作的消息,通常在交易策略中调用。
Order将strategy的逻辑做出的决策转换为适合broker执行操作的消息。通过以下方式完成:
创建 ,通过strategy 的方法:buy sell 和close 都可以返回Order的实例
取消,通过strategy的方法:cancel 也可以产生Order实例
通知,notify_order 的方法,也返回Order 实例
订单还作为反馈给用户的通信方法,通知代理中的运行情况

(5)经纪人(Broker):

通过设置回测的初始自己、佣金费率、税收费率、滑点率等交易条件,模拟不同的订单类型,限价订单,控制订单的有效期,并根据现金检查订单,计算每次交易的现金和权益,保存交易数据。
Trade :backtrader会自动记录每笔交易的详细信息,包括买入价格、卖出价格、手续费等。用户可以通过这些交易记录进行后续的分析和统计。
Position :仓位管理 。

(6)策略评估(Analyzers):

用于分析交易策略的利润和风险,分析交易系统的绩效。
内置各类评价指标,可以加入到评测对象中,对结果进行绩效分析,分析指标:年度回报率,卡尔玛比率,最大回撤,资金杠杆,仓位资金,组合投资值等,是对策略的效果评估参数。

(7)观察者(Observers):

用于记录交易过程,包括现金、权益、费用以及交易动作、买卖订单等数据。

(8)回测引擎(Backtesting Engine):

cerebro.run()
backtrader提供了一个强大的回测引擎,用户可以通过指定回测时间段和初始资金等参数来进行策略回测。回测引擎会模拟真实的交易环境,并根据用户定义的策略进行交易。

(9)绘图(Plot):

分析和可视化(Analysis and Visualization):
backtrader提供了多种分析工具和可视化功能,用户可以对回测结果进行详细的分析和可视化展示,可以增加图示内容,包括收益曲线、风险指标、交易位置等。
通过图形的方式显示交易测量回测的结果,绘图显示的结果包括三部分类型:现金及权益、交易损益、买卖动作。

绘图设置通过plotinfo来设置,其参数主要有:plot(是否绘图,默认为True),subplot(是否单独窗口绘图,默认为True,MA类指标该参数为False),plotname(指标图名,默认为指标类名),plotabove(绘图位置在数据上方,默认为False),plotlinelabels, plotymargin, plotyticks,plothlines, plotyhlines, plotforce。

3.代码示例

做一个最简单的SMA测试示例。
取100个股票,进行测试,测试的时间范围从2016年到2020年,一共5年的数据。
在策略中的init()初始化定义了Indicator ,在next()中买卖操作。
增加了Observer和Analyzer ,把大多数的监控绩效的指标都加入了。

#!/usr/bin/env python
import datetime
import pandas as pd
import numpy as np
import pymysql

import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
from sqlalchemy import create_engine

engine_ts = create_engine(
    'mysql+pymysql://user:pwd@ip:3306/dbname?charset=utf8&use_unicode=1')

def get_stock_code():
    sql = "select t.ts_code from ts_stock_basic t where t.list_status='L' limit 100;"

    stock_data = pd.read_sql(sql, con=engine_ts)
    return stock_data

def get_code(stock_code):
    sql = "select t.trade_date as date,t.`open`,t.high,t.low,t.`close`,t.vol,t.amount from ts_stock_daily t where  \
          t.ts_code='" + stock_code + "' and t.trade_date > '2016-01-01' and t.trade_date < '2020-12-31' order by date ;"

    # print(sql)
    # stock_data = pd.read_sql(sql, con=engine_ts,index_col="date")
    # 因为BackTrader日期类型必须是datetime ,从数据库中读取的日期类型是date 。
    # 读数据,先不设置索引
    stock_data = pd.read_sql(sql, con=engine_ts)  # ,index_col="date"

    # 增加一列,select 字段名是date,赋值到trade_date,同时转datetime类型
    stock_data['trade_date'] = pd.to_datetime(stock_data['date'], format='%Y%m%d %H:%M:%S')

    # 删除原来的date列
    stock_data.drop(columns=['date'])

    # 新datetime列作为索引列
    stock_data.set_index(['trade_date'], inplace=True)

    # 索引列改名
    stock_data.index.name = 'date'

    # 按backtrader 格式要求,第7列openinterest ,也可以不用
    # stock_data['openinterest'] = 0

    data = stock_data.sort_index(ascending=True)

    #engine_ts.dispose()
    return data

class OrderObserver(bt.observer.Observer):
    lines = ('created', 'expired',)

    plotinfo = dict(plot=True, subplot=True, plotlinelabels=True)

    plotlines = dict(
        created=dict(marker='*', markersize=8.0, color='lime', fillstyle='full'),
        expired=dict(marker='s', markersize=8.0, color='red', fillstyle='full')
    )

    def next(self):
        for order in self._owner._orderspending:
            if order.data is not self.data:
                continue

            if not order.isbuy():
                continue

            # Only interested in "buy" orders, because the sell orders
            # in the strategy are Market orders and will be immediately
            # executed

            if order.status in [bt.Order.Accepted, bt.Order.Submitted]:
                self.lines.created[0] = order.created.price

            elif order.status in [bt.Order.Expired]:
                self.lines.expired[0] = order.created.price

# CrossOver Strategy
class St_CrossOver(bt.Strategy):
    params = (
        ('smaperiod', 15),
        ('limitperc', 1.0),
        ('valid', 7),
        ('print', False),
    )

    def log(self, txt, dt=None):
        ''' Logging function fot this strategy'''
        dt = dt or self.data.datetime[0]
        if isinstance(dt, float):
            dt = bt.num2date(dt).date() # no Hour mintue second
        if self.params.print :
            print('%s, %s' % (dt.isoformat(), txt))

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # Buy/Sell order submitted/accepted to/by broker - Nothing to do
            self.log('ORDER ACCEPTED/SUBMITTED', dt=order.created.dt)
            self.order = order
            return

        if order.status in [order.Expired]:
            self.log('BUY EXPIRED')

        elif order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (order.executed.price,
                     order.executed.value,
                     order.executed.comm))

            else:  # Sell
                self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                         (order.executed.price,
                          order.executed.value,
                          order.executed.comm))

        # Sentinel to None: new orders allowed
        self.order = None

    def __init__(self):
        # SimpleMovingAverage on main data
        # Equivalent to -> sma = btind.SMA(self.data, period=self.p.smaperiod)
        sma = btind.SMA(period=self.p.smaperiod)

        # CrossOver (1: up, -1: down) close / sma
        self.buysell = btind.CrossOver(self.data.close, sma, plot=True)

        # Sentinel to None: new ordersa allowed
        self.order = None

    def next(self):
        if self.order:
            # pending order ... do nothing
            return

        # Check if we are in the market
        if self.position:
            if self.buysell < 0:
                self.log('SELL CREATE, %.2f' % self.data.close[0])
                self.sell()

        elif self.buysell > 0:
            plimit = self.data.close[0] * (1.0 - self.p.limitperc / 100.0)
            valid = self.data.datetime.date(0) + \
                datetime.timedelta(days=self.p.valid)
            self.log('BUY CREATE, %.2f' % plimit)
            self.buy(exectype=bt.Order.Limit, price=plimit, valid=valid)


def runstrat(stock_code):
    cerebro = bt.Cerebro()
    # 初始资金 100,000,000
    cerebro.broker.setcash(100000.0)
    # 佣金,双边各 0.0003
    cerebro.broker.setcommission(commission=0.0003)
    # 滑点:双边各 0.0001
    cerebro.broker.set_slippage_perc(perc=0.0001)

    # 获取数据
    stock_df = get_code(stock_code)

    start_date = datetime.datetime(2016, 1, 1)  # 回测开始时间
    end_date = datetime.datetime(2020, 12, 31)  # 回测结束时间
    data = bt.feeds.PandasData(dataname=stock_df, fromdate=start_date, todate=end_date)  # 加载数据

    cerebro.adddata(data)

    cerebro.addobserver(OrderObserver)
    cerebro.addstrategy(St_CrossOver)

    tframes = dict(
        days=bt.TimeFrame.Days,
        weeks=bt.TimeFrame.Weeks,
        months=bt.TimeFrame.Months,
        years=bt.TimeFrame.Years)

    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='mysharpe')
    cerebro.addanalyzer(bt.analyzers.DrawDown,_name = 'mydrown')
    cerebro.addanalyzer(bt.analyzers.AnnualReturn,_name = 'myannualreturn')
    cerebro.addanalyzer(bt.analyzers.SQN,_name = 'mysqn')
    cerebro.addanalyzer(bt.analyzers.TradeAnalyzer,_name = 'mytradeanalyzer')
    cerebro.addanalyzer(bt.analyzers.PositionsValue,_name = 'mypositionvalue')
    cerebro.addanalyzer(bt.analyzers.Returns,_name = 'myreturns')
    cerebro.addanalyzer(bt.analyzers.LogReturnsRolling,timeframe=tframes['years'],_name = 'mylogreturnsrolling')
    cerebro.addanalyzer(bt.analyzers.Transactions, _name='mytransactions')

    thestrats = cerebro.run()
    thestrat = thestrats[0]

    print('Sharpe Ratio:', thestrat.analyzers.mysharpe.get_analysis())
    print('DrawDown:', thestrat.analyzers.mydrown.get_analysis())
    print('AnnualReturn:', thestrat.analyzers.myannualreturn.get_analysis())
    print('SQN:', thestrat.analyzers.mysqn.get_analysis())
    print('TradeAnalyzer:', thestrat.analyzers.mytradeanalyzer.get_analysis())
    print('PositionsValue:', thestrat.analyzers.mypositionvalue.get_analysis())
    print('Returns:', thestrat.analyzers.myreturns.get_analysis())
    print('LogReturnsRolling:', thestrat.analyzers.mylogreturnsrolling.get_analysis())
    print('Transactions:', thestrat.analyzers.mytransactions.get_analysis())

    #cerebro.plot()


if __name__ == '__main__':
    
    t1 = datetime.datetime.now()
    stock_data = get_stock_code()
    
    for i in range(len(stock_data)):
        print(stock_data.loc[i, 'ts_code'])
        runstrat(stock_data.loc[i, 'ts_code'])
    
    t2 = datetime.datetime.now()
    print('Spend time:', t2 - t1)
    engine_ts.dispose()
    print('ok!')

详细结果内容多,就不展示了。
结果是用了32.59秒完成计算,100个股票,5年的数据,速度还可以。

Spend time: 0:00:32.591037
ok!

4.小结

backtrader的整体架构是基于事件驱动的,用户通过编写策略类来定义交易逻辑,并通过回测引擎进行策略回测和分析。
通过上面的比较全面的功能测试,基本上覆盖前期学习的backtrader主要功能,完成了一个自定义的策略回测验证。

在不考虑数据采集的情况下,假设数据全部在数据库中,需要后期完成的工作很多:

  • 组合策略的定义,肯定不能是简单的SMA,可以结合MACD /RSI/KDJ/ADX 等等指标。
  • 时间周期的定义,触发不同指标的效果。
  • 策略评估结果保存入库后,进行横向比较。
  • 参数调优,最简单的如前篇文章,测试胜率和盈亏比组合,组合参数的递增或递减,绩效结果对比。
  • 黑天鹅事件,比如千股跌停的情况,异常极端情况的风险控制,2008年6月次贷危机世界经济危机,2015年6月到8月去杠杆,2016年1月熔断机制上线,还有今年2月5日 。
  • 加仓机制实现
  • 止损机制实现
  • 止盈机制实现
  • 仓位管理实现
  • 对于不同走势定义不同的策略,如短期打板策略,需要看成交量、换手率,严格的止盈止损。
  • 策略模块化,可以是内置类
  • 日志,绩效结果模块化,到数据库
  • 绩效参考基准,比如沪深500

对于自定义的回测功能或控制内容,欢迎大家可以留言探讨。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2037597.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FPGA学习笔记-1 FPGA原理与开发流程

1 初识FPGA 文章目录 1 初识FPGA1.1 基本认知1.1.1 什么是FPGA&#xff1f;1.1.2 什么是HDL&#xff1f;什么是Verilog&#xff1f;1.1.3 硬件开发与软件开发1.1.4 FPGA与其他硬件的对比1.1.5 FPGA优势与局限性1.1.6 FPGA的应用1.1.7 FPGA的学习之路 1.2 FPGA开发流程1.2.1 一般…

【学习AI-相关路程-概念了解-基础概念-正负样本-模型-文件结尾-卷积-yolov8模型-概念学习】

【学习AI-相关路程-概念了解-基础概念-正负样本-模型-文件结尾-卷积-yolov8模型-概念学习】 1、前言2、了解正负样本1-定义2-正样本3-负样本4-举例 3、模型这个概念1- 模型的定义2- 模型的训练3- 模型的推理4- 模型的评估5- 模型的类型6- 常见的模型 4、以这样 .yaml 结尾文件是…

以太坊私有链 搭建及相关操作

文章目录 1、创建私有链1.1 创建配置文件1.2 初始化私有链1.3 启动私有链1.4 添加节点1.4.1 启动节点A1.4.2 启动节点B1.4.3 查看节点A信息1.4.4 节点B主动加入到节点A1.4.5 查看已连接的节点数1.4.6 查看其它节点信息2、以太坊挖矿相关操作2.1 查看账户2.2 创建账户2.3 查看账…

RUST实现远程操作电脑手机

简介&#xff1a; Rust Desk 是一个开源的远程桌面软件&#xff0c;能够完全替代向日葵和ToDesk的功能&#xff0c;包括电脑控制电脑、电脑控制手机、手机控制电脑等。它是完全免费的。 下载&#xff1a; 需要下载 Rust Desk 的服务端和客户端安装包。 安装&#xff1a; 服务…

PHP移动端商城分销全平台全端同步使用

&#x1f4f1;【掌中购物新纪元&#xff1a;探索移动端购物商城系统的无限魅力】&#x1f6cd;️ &#x1f680; 随时随地&#xff0c;购物自由新体验 在这个快节奏的时代&#xff0c;移动端购物商城系统彻底颠覆了传统购物方式&#xff0c;让消费者享受到了前所未有的便捷与…

探索RPA自动化流程机器人在财务领域的应用

随着科技的不断发展&#xff0c;企业对于流程自动化的需求日益增长。在此背景下&#xff0c;RPA机器人流程自动化技术应运而生&#xff0c;并在财务领域展现出强大的应用潜力。RPA能够模拟人类在计算机上的操作&#xff0c;自动化处理大量重复、繁琐的财务流程&#xff0c;为企…

linux共有云主机ssh升级(以openEuler22.03为例)

目录 为什么要升级ssh怎么查看CVE如何查找新版本的opensshOpenSSH 升级ssh步骤1. 下载源码包2. 备份旧文件防止升级失败3. 停止并卸载旧ssh4. 解压、编译、编译安装新ssh5. 修改systemd文件以便systemctl使用sshd6. 测试 为什么要升级ssh openssh作为使用最为广泛的linux下ssh…

机器学习——线性回归(sklearn)

目录 一、认识线性回归 1. 介绍 2. 多元线性回归的基本原理&#xff08;LinearRegression&#xff09; 二、多重共线性 1. 介绍 2. 多重共线性详细解释 三、岭回归&#xff08;解决多重共线性问题&#xff09; 1. 模型推导 2. 选取最佳的正则化参数取值 四、Lasso&am…

(寄中寄) docker destop 的wsl问题——记一次在win10虚拟机的上的启动docker

&#x1f3aa;&#x1f3a2;&#x1f3a1;&#x1f3a0;&#x1f921;&#x1f981; 在win10上可能可以用docker&#xff0c;不过在win10上用docker有点不可能 wsl在windows中可能需要安装&#xff0c;不过wsl在windows安装有点不可能 应该是不用安装吧 可能需要重启 然后 …

移动运维APP项目建设:重塑运维服务新范式

在当今信息化高速发展的时代&#xff0c;信息系统已成为企业运营的核心支撑。为确保信息系统稳定、高效运行&#xff0c;运维团队面临着前所未有的挑战。传统运维方式受限于固定场所和设备&#xff0c;难以满足随时随地访问、快速响应等现代运维需求。因此&#xff0c;依托现有…

uniapp自定义navigationBar

最终效果&#xff1a; 一、关闭默认导航栏 pages.json文件中&#xff0c;对单个页面关闭 "navigationStyle": "custom" "pages": [ //pages数组中第一项表示应用启动页&#xff0c;参考&#xff1a;https://uniapp.dcloud.io/collocation/pag…

IP地址证如何实现HTTPS访问?(内网IP、公网IP)

IP地址证书&#xff08;全称为IP地址的SSL/TLS证书&#xff09;是实现通过IP地址进行HTTPS访问的关键。以下是实现这一目标的详细步骤&#xff1a; 一、选择证书颁发机构&#xff08;CA&#xff09; 1.选择支持IP证书的CA&#xff1a;并非所有证书颁发机构都提供为IP地址颁…

(计算机网络)网络层

目录 一.网络层提供哪种服务 二.两种服务的比较 三.ip协议 四.ip地址 五.ip地址的分类 六.子网掩码 七.路由器介绍 一.网络层提供哪种服务 1.ip地址--唯一的标识互联网上的某一台主机 2. 虚电路&#xff1a;虚拟的电路 二.两种服务的比较 ip数据报&#xff0c;不需要建…

航空航天构型管理

构型管理(CM)被定义为在产品的生命周期中应用的SE技术和管理规程。CM的五个原则是&#xff1a;CM计划与执行、配置识别、配置变更和差异控制、配置状态核算和配置验证。 广义上的构型管理规划和管理是有效实施配置管理的关键。特别是在不同项目之间的差异中&#xff0c;构型管理…

网络协议九 应用层 HTTPS

一 什么是 HTTPS 二 什么是 SSL/TLS 协议 &#xff0c;TLS 是 SSL 升级后的名字 三. TLS 协议 工作在那一层 四 。OpenSSL 是 SSL/TLS协议的开源实现。 五。重点 HTTPS 的通讯过程 六 TLS 1.2 的连接过程 1. client hello 是浏览器发送给服务器的第一条信息&#xff0c; 是客户…

Ubuntu24.04安装 Mysql 并修改root密码 + 配置

参考文章&#xff1a;Ubuntu安装MySQL 一、下载并安装 MySQL 1、安装 mysql 服务端 yammiemy-pc >/opt $ sudo apt-get install mysql-server 2、安装 mysql 客户端 yammiemy-pc >/opt $ sudo apt-get install mysql-client 3、安装程序编译时连接的库 yammiemy-pc &…

【06】JVM是如何实现反射的?

为了保证框架的可扩展性&#xff0c;往往借助 Java 的反射机制&#xff0c;根据配置文件来加载不同的类。Spring 框架的依赖反转&#xff08;IoC&#xff09;&#xff0c;便是依赖于反射机制。 反射调用的实现 这里主要是以【方法的反射调用】来进行剖析 public final class…

cocosUI多分辨率适配

需求&#xff1a;由于各个设备的分辨率和尺寸并不一样&#xff0c;所以需要一套适配系统去很好的针对不同的设备分辨率或尺寸进行适配&#xff0c;以给玩家一个很好的游戏体验。 目前的主流适配方案 目前&#xff0c;针对不同设备的适配&#xff0c;主流的方案通常包括以下几种…

OpenHarmony4.1上初体验rust

OpenHarmony4.1上初体验rust 前言一、准备工作二、初步调研三、初步尝试运行测试demo 四、尝试构建自己的hello world五、与C、C的交互总结 前言 由于后续可能要做rust基于OpenHarmony的开发工作&#xff0c;于是先开始一些调研性的工作&#xff0c;rust了解的内容可以参考该文…

雷达气象学(6)——径向速度图分析

文章目录 6.1 速度场分析基础6.1.1 速度图分析的基本方法6.1.2 练习&#xff1a;整层为均匀西风6.1.3 练习&#xff1a;风向随高度顺转 6.2 水平均匀风场的典型图像6.3 典型天气系统的判别6.3.1 锋面&#xff08;切变线&#xff09;系统6.3.1.1 冷锋&#xff08;冷式切变线&…