news 2026/10/17 8:51:42

Unity跨平台二维码生成与识别实战:Zxing工程化落地指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Unity跨平台二维码生成与识别实战:Zxing工程化落地指南

1. 项目概述:为什么在Unity里搞二维码不是“加个插件就完事”?

Unity里做二维码生成和识别,表面看就是调个Zxing库、拖两个脚本的事——我最早接手这个需求时也是这么想的。结果在某次AR导览项目中,现场测试阶段直接翻车:安卓端扫码延迟高到用户反复晃手机,iOS上生成的二维码在弱光下根本扫不出来,更别提WebGL构建后整个识别模块直接报错退出。后来花两周时间把Zxing在Unity里的每个坑都踩了一遍,才明白这事根本不是“功能有没有”,而是“在什么平台、什么分辨率、什么光照条件下,能稳定跑出多少帧、识别率多少、内存涨多少”。

核心关键词全在这里了:Unity、二维码生成、二维码识别、Zxing、跨平台兼容性、实时性能、移动端适配。这不是一个纯工具调用问题,而是一个典型的Unity工程化落地场景——你要面对的是不同GPU架构的纹理上传机制、不同摄像头API的帧率控制策略、不同平台对.NET版本的限制,以及Zxing底层算法在Unity Mono/IL2CPP环境下的行为漂移。

适合谁来看?如果你是刚从Unity基础教程毕业、正准备接第一个带扫码功能的商业项目(比如展会导览App、设备维修AR助手、校园迎新小程序),或者你已经写好了脚本但发现“在编辑器里好好的,一打包就崩”,那这篇就是为你写的。它不讲Zxing源码怎么写,但会告诉你:为什么Zxing.Net的Standard版在Unity 2021+里必须手动降级到4.1.5;为什么用Texture2D.ReadPixels抓摄像头帧比用WebCamTexture.GetPixelBuffer快3倍;为什么生成带Logo的二维码时,必须把Logo尺寸控制在模块数的1/7以内,否则微信扫码直接失败。所有结论都来自真机实测数据,不是文档翻译。

2. 技术选型与架构设计:为什么Zxing是当前最稳的选择,以及它到底“稳”在哪

2.1 Zxing在Unity生态中的不可替代性

先说结论:目前没有比Zxing更成熟的纯C#二维码方案。有人试过用OpenCV+Unity插件,但得自己编译Android/iOS的.so/.a文件,光NDK版本兼容就耗掉三天;也有人想用JavaScript的qrcode.js走WebGL通道,结果发现Unity WebGL的摄像头权限模型和浏览器完全不同,连获取视频流都得绕三道弯。Zxing的优势在于它原生就是C#写的,且社区维护了专门针对Unity的封装层(zxing.unity),关键点有三个:

  • 零依赖运行时:Zxing.Core.dll不依赖System.Drawing(Unity里这玩意儿压根没实现),所有图像处理用的是纯数组操作,避免了Unity 2019+之后对GDI+的屏蔽;
  • 可裁剪性强:Zxing支持按需引用子模块,比如你只做识别,就只引用ZXing.Common、ZXing.QrCode、ZXing.Datamatrix三个DLL,体积能压到180KB以内;如果还要生成,再加ZXing.Rendering,总包也不超300KB;
  • 跨平台解码一致性:同一张模糊二维码图,在安卓、iOS、Windows编辑器里解码结果完全一致,这点在医疗设备扫码场景里是生死线——不能出现“医生在iPad上扫出来是ID-12345,护士在安卓平板上扫出来是ID-12346”的情况。

提示:千万别用NuGet里搜到的“ZXing.Net”最新版(v0.16.12)。它默认引用System.Drawing.Common,Unity打包时会报错CS0234:“命名空间‘System.Drawing’中不存在类型或命名空间‘Imaging’”。必须手动下载Zxing官方GitHub Release页的zxing.unity包(截至2024年,推荐用v0.16.8),里面已预编译好Unity专用版本。

2.2 架构分层:为什么要把生成和识别拆成两个独立系统

很多新手会把生成和识别写在一个MonoBehaviour里,比如挂个脚本,上面放InputField输内容,下面放RawImage显示二维码,再加个WebCamTexture识别——这在编辑器里能跑,但一到真机就出问题。根本原因是生成和识别的资源生命周期完全不同:

  • 生成模块:是CPU密集型任务,但执行频率低(用户点“生成”才触发一次),可以接受200ms延迟,重点在输出质量(容错率、清晰度);
  • 识别模块:是实时IO密集型任务,要求每秒至少处理15帧(低于12帧人眼就感觉卡顿),重点在吞吐量和稳定性(不能因某帧解码失败就整个线程挂掉)。

所以我最终采用的架构是三层分离:

  1. 数据层(Data Layer):定义统一的QRCodeData类,包含content(原始字符串)、errorCorrection(L/M/Q/H等级)、size(像素宽高)、logoTexture(可选Logo贴图)等字段,所有模块只认这个结构;
  2. 服务层(Service Layer):QRCodeGenerator负责生成,QRCodeScanner负责识别,两者完全解耦,通过事件(如OnQRCodeGenerated、OnQRCodeDetected)通信;
  3. 表现层(Presentation Layer):UIManager管理RawImage显示、InputField输入、Button点击逻辑,不碰任何Zxing代码。

这种设计让后续扩展变得极其简单:比如要加条形码识别,只需新增BarcodeScanner类,复用同一套事件系统;要换生成引擎(比如用SkiaSharp画更精细的二维码),只改QRCodeGenerator内部实现,UI层一行代码都不用动。

2.3 平台适配策略:为什么安卓/iOS/WebGL要用三套不同的摄像头接入方案

Zxing本身不处理摄像头,它只负责解码Bitmap。所以真正的难点在“怎么把手机摄像头画面变成Zxing能吃的Bitmap”。这里踩过的坑最多:

  • 安卓端:必须用AndroidJavaObject调用Camera2 API,不能用Unity自带的WebCamTexture。因为WebCamTexture在安卓上默认用SurfaceView渲染,Zxing读取时会遇到YUV转RGB的色彩失真,导致识别率暴跌30%。正确做法是用Camera2的ImageReader获取NV21格式帧,再用JNI桥接层转成byte[]传给Zxing;
  • iOS端:WebCamTexture可用,但必须设置requestedFPS=30(不能用默认的0),且要在Awake()里预热摄像头(调用WebCamTexture.Play()后等待两帧再开始捕获),否则首帧识别率极低;
  • WebGL端:根本不能用WebCamTexture!Unity WebGL的摄像头API受限于浏览器安全策略,必须用HTML5的MediaDevices.getUserMedia()获取video元素,再用Canvas2D.drawImage()逐帧绘制到Texture2D。这个过程有500ms左右延迟,所以WebGL版必须开启“连续识别模式”(即每3帧识别一次,而非逐帧),否则用户会觉得“扫码反应慢半拍”。

注意:所有平台的摄像头分辨率必须锁定为1280x720。实测发现,用1920x1080分辨率时,Zxing解码单帧耗时从8ms飙升到22ms,且安卓低端机内存直接爆掉。1280x720是性能和精度的黄金平衡点——既能保证二维码模块(module)宽度≥3像素(Zxing最低识别阈值),又不会让CPU持续满载。

3. 核心功能实现:从零写出可商用的生成与识别模块

3.1 二维码生成模块:不只是“画个方块”,而是控制容错率与视觉权重

生成模块的核心是ZXing.QrCode.QRCodeWriter类,但直接用它会掉进两个大坑:一是默认容错率是M(Medium,15%),实际商用场景需要Q(Quartile,25%)甚至H(High,30%);二是生成的二维码是纯黑白,加上Logo后边缘发虚,微信扫不出来。解决方案如下:

第一步:动态计算最佳容错等级
不能硬编码ErrorCorrectionLevel.H。要根据输入内容长度动态选择:

public static ErrorCorrectionLevel GetBestECLevel(string content) { int length = Encoding.UTF8.GetByteCount(content); if (length <= 50) return ErrorCorrectionLevel.H; // 短文本用最高容错 if (length <= 200) return ErrorCorrectionLevel.Q; return ErrorCorrectionLevel.M; // 超长文本降级,避免模块太密 }

原理很简单:容错率越高,二维码里用于纠错的模块越多,有效信息模块越少。短文本冗余空间大,拉高容错能扛住Logo遮挡;长文本本身模块就密,再加高容错会导致模块尺寸小于3像素,反而无法识别。

第二步:生成带Logo的二维码(非简单贴图)
很多人用“生成二维码→Texture2D.Resize→DrawTexture覆盖Logo”三步法,结果Logo边缘全是锯齿。正确做法是用ZXing.Rendering.BitmapRenderer的自定义绘制逻辑:

var writer = new QRCodeWriter(); var bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size, hints); // 创建带Alpha通道的RenderOptions var options = new RenderOptions { Foreground = Color.black, Background = Color.white, ModuleSize = 1, // 关键!强制每个模块占1像素 QuietZone = 4 // 静区留4模块宽,防Logo溢出 }; var bitmap = BitmapRenderer.Render(bitMatrix, options); // 此时bitmap是纯黑白Bitmap,接下来用Texture2D.DrawTexture精准覆盖Logo区域

关键参数ModuleSize = 1确保每个二维码模块严格对应1个像素,这样后续用Graphics.Blit把Logo贴到中心时,边缘不会出现半像素模糊。实测下来,Logo尺寸控制在二维码总宽的1/7(比如500x500二维码,Logo最大71x71),微信/支付宝扫码成功率>99.2%。

第三步:解决Unity纹理压缩导致的识别失败
生成的Texture2D如果设为ETC2或ASTC压缩格式,Zxing读取时会因颜色失真无法识别。必须在生成后强制设置:

texture2D.filterMode = FilterMode.Point; // 关闭双线性插值 texture2D.wrapMode = TextureWrapMode.Clamp; texture2D.Compress(false); // 关键!禁用压缩

这会让纹理内存占用翻倍,但换来的是100%识别率。商用项目里,宁可多占2MB内存,也不能让用户扫不出码。

3.2 二维码识别模块:如何把Zxing的“秒级识别”压到“毫秒级”

识别模块的瓶颈从来不在Zxing算法本身,而在“怎么喂数据给它”。Zxing的Decode方法接收的是LuminanceSource,而Unity里最常用的Texture2D.ReadPixels()方法,单帧耗时高达15~28ms(取决于分辨率)。优化路径有三条:

路径一:用WebCamTexture.GetPixelBuffer()替代ReadPixels(安卓/iOS专用)
这是性能提升最大的改动。WebCamTexture自带GPU缓冲区,GetPixelBuffer()直接返回NativeArray ,无需CPU拷贝:

// 每帧执行 if (webCamTexture.didUpdateThisFrame) { NativeArray<byte> buffer = webCamTexture.GetPixelBuffer(); // buffer里是RGBA格式,Zxing要灰度图,用SIMD指令快速转换 ConvertRGBAToGrayscale(buffer, grayscaleBuffer); var source = new RGBLuminanceSource(grayscaleBuffer, width, height); var result = barcodeReader.Decode(source); }

实测数据:1280x720分辨率下,ReadPixels平均22.3ms,GetPixelBuffer+SIMD转换仅4.7ms,性能提升4.7倍。

路径二:帧率自适应采样(全平台通用)
不追求“每帧都识别”,而是根据上一帧结果动态调整:

  • 如果上一帧识别成功,下一帧跳过识别(用户已扫到,没必要持续占CPU);
  • 如果连续3帧失败,自动降低分辨率到960x540再试;
  • 如果连续5帧失败,触发“强光/暗光”检测(分析灰度直方图方差),提示用户“请调整光线”。

路径三:Zxing参数精调(影响识别率的关键)
Zxing的MultiFormatReader默认启用所有码制(QR、EAN、UPC等),但商用项目99%只扫QR码。关闭无关码制能提速40%:

var reader = new MultiFormatReader(); var hints = new Dictionary<DecodeHintType, object>(); hints[DecodeHintType.POSSIBLE_FORMATS] = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }; hints[DecodeHintType.TRY_HARDER] = true; // 强制开启复杂场景识别 hints[DecodeHintType.PURE_BARCODE] = false; // 允许图片中有干扰物 reader.SetHints(hints);

特别注意TRY_HARDER=true:它会让Zxing在首次识别失败后,自动尝试旋转45°、90°、135°再解码,对歪斜二维码识别率提升显著(从68%→92%)。

3.3 跨平台构建配置:那些Unity打包时不会告诉你的隐藏开关

即使代码写得再完美,打包配置错一个,整个模块就废。以下是各平台必须检查的五项设置:

平台必须开启的设置为什么必须开不开的后果
AndroidPlayer Settings → Other Settings → Target Architectures → ARM64Zxing的SIMD优化只在ARM64生效ARMv7下识别速度慢2倍,且部分旧机型崩溃
iOSPlayer Settings → Publishing Settings → Strip Engine Code → DisabledZxing依赖的部分反射API会被误删打包后扫码功能完全消失,Xcode里无报错
WebGLPlayer Settings → Publishing Settings → Compression Format → DisabledLZ4压缩会破坏Texture2D的像素排列生成的二维码全是乱码,识别返回null
AllEdit → Project Settings → Player → Configuration → Api Compatibility Level → .NET Standard 2.1Zxing v0.16.8最低要求Unity 2021+项目会编译失败
AllBuild Settings → Build Type → Development Build + Script Debugging识别失败时能看到Zxing内部日志线上问题无法定位,只能靠猜

实操心得:每次换Unity版本(比如从2021.3升到2022.3),第一件事不是改代码,而是重新检查这五项。我曾因漏关WebGL的Compression Format,花了两天排查“为什么本地能扫,发布后扫不了”的问题。

4. 实战问题排查与避坑指南:那些文档里绝不会写的血泪经验

4.1 常见问题速查表(按发生频率排序)

问题现象根本原因解决方案验证方式
安卓端扫码卡顿,CPU占用90%+WebCamTexture分辨率设为1920x1080,且未启用GetPixelBuffer在Awake()里强制设置webCamTexture.requestedWidth=1280; requestedHeight=720;,并改用GetPixelBuffer用Android Studio Profiler看CPU火焰图,确认Zxing.Decode调用是否集中在主线程
iOS上首次扫码失败率>80%摄像头未预热,首帧YUV数据不完整在Start()里加webCamTexture.Play(); yield return new WaitForSeconds(0.1f);,等两帧后再启动识别循环用Xcode Console看是否有"AVCaptureSession startRunning"日志
WebGL发布后二维码显示为灰色方块Texture2D未设置filterMode=Point,浏览器缩放导致像素混合在Texture2D.CreateExternalTexture()后立即执行texture.filterMode = FilterMode.Point;在浏览器开发者工具里检查Canvas元素,确认是否出现CSS transform缩放
生成的二维码在微信里扫出乱码输入字符串含中文但未指定UTF-8编码writer.encode(content, ..., new Dictionary<EncodeHintType, object>{{EncodeHintType.CHARACTER_SET, "UTF-8"}})用Zxing官方在线解码器(zxing.org)上传生成图,看是否返回原文
添加Logo后识别率暴跌至30%Logo尺寸超过二维码模块数的1/7,且未设置QuietZone≥4用QRCodeEncodingOptions.QuietZone = 4,并计算Logo最大尺寸:maxLogoSize = (int)(qrSize / 7)用Photoshop打开生成图,测量Logo外边距是否≥4个模块宽度

4.2 那些只有真机测试才会暴露的诡异问题

问题1:三星S22 Ultra的“超级夜景模式”导致扫码失效
现象:其他安卓机正常,唯独三星S22在暗光下扫码失败。抓Log发现Zxing返回“Could not decode matrix”。
原因:三星相机固件在夜景模式下会自动叠加多帧降噪,WebCamTexture拿到的是合成后的模糊帧。
解法:在AndroidManifest.xml里加权限声明,并在运行时请求android.permission.CAMERA_DISABLE_EFFECTS(需自定义Android插件)。更简单的方案是检测到三星设备时,强制关闭夜景:webCamTexture.requestedFPS = 15;(低帧率可抑制多帧合成)。

问题2:iPhone 14 Pro的“灵动岛”区域遮挡二维码
现象:用户把手机横屏扫码,灵动岛黑条正好盖住二维码顶部,识别失败。
原因:WebCamTexture的activeTextureRect默认是全屏,但灵动岛区域实际不可用。
解法:动态计算安全区域:

#if UNITY_IOS Rect safeArea = Screen.safeArea; float x = safeArea.x / Screen.width; float y = safeArea.y / Screen.height; float width = safeArea.width / Screen.width; float height = safeArea.height / Screen.height; // 将safeArea映射到WebCamTexture坐标系,裁剪掉灵动岛区域 #endif

问题3:Unity 2022.3的IL2CPP下Zxing反射失败
现象:编辑器里一切正常,iOS真机打包后Zxing报“System.Reflection.TargetInvocationException”。
原因:IL2CPP默认剪枝掉Zxing用到的System.Type.GetMethod()反射调用。
解法:在Assets/Plugins/LinkerConfig.xml里添加保留规则:

<linker> <assembly fullname="zxing.unity"> <type fullname="ZXing.Common.DecoderResult" preserve="all"/> <type fullname="ZXing.QrCode.Internal.Decoder" preserve="all"/> </assembly> </linker>

4.3 性能压测实录:不同场景下的真实数据

我用一台红米Note 12(骁龙4 Gen1)和iPhone 13(A15)做了72小时连续压测,数据如下:

场景设备分辨率帧率平均识别耗时内存增量识别成功率
弱光室内(照度50lux)红米Note 121280x72018fps12.4ms+8.2MB89.7%
强光户外(照度10000lux)iPhone 131280x72028fps6.1ms+5.3MB98.2%
二维码倾斜45°红米Note 121280x72015fps28.7ms(启用TRY_HARDER)+12.1MB91.3%
带Logo二维码(占比1/7)iPhone 131280x72025fps7.3ms+6.8MB96.5%
连续扫码100次(同一码)红米Note 121280x72020fps8.9ms(首帧)→ 5.2ms(第100帧)+3.1MB(稳定)100%

关键发现:识别耗时不是线性增长,而是随连续使用下降。这是因为Zxing的DecoderResult缓存机制在起作用——同一张二维码被多次识别后,会缓存其定位点(Finder Pattern)位置,后续解码直接跳过定位步骤。所以商用App里,如果用户频繁扫同一个码(比如设备上的固定SN码),实际体验会越来越快。

5. 进阶技巧与生产环境加固:让二维码模块真正扛住商用压力

5.1 识别结果去重与防抖:解决“扫一下弹出十次”的尴尬

用户手一抖,同一张码可能在100ms内被连续识别5次。如果每次识别都触发事件(比如跳转页面),就会出现“页面疯狂闪退再进入”的灾难。标准解法是加时间窗口去重:

private string lastContent = ""; private float lastTime = 0f; private const float DEBOUNCE_TIME = 0.5f; // 500ms内相同内容只触发一次 public void OnQRCodeDetected(string content) { if (content == lastContent && Time.time - lastTime < DEBOUNCE_TIME) return; lastContent = content; lastTime = Time.time; // 此处触发业务逻辑,比如EventSystem.current?.SubmitEvent(...) }

但更优方案是结合二维码内容特征做哈希去重:

private long lastHash = 0; private long CalculateContentHash(string content) { unchecked // 防溢出 { long hash = 23; foreach (char c in content) hash = hash * 31 + c; return hash; } } // 使用lastHash替代lastContent比较,内存占用更低,且避免字符串GC

5.2 安全加固:防止恶意二维码触发危险操作

二维码本质是字符串载体,攻击者可构造javascript:alert('xss')或intent://...链接。商用项目必须做白名单校验:

public static bool IsValidQRContent(string content) { if (string.IsNullOrEmpty(content)) return false; // 只允许特定协议 if (content.StartsWith("https://") || content.StartsWith("http://")) return IsDomainWhitelisted(new Uri(content).Host); // 只允许纯数字ID(如设备SN) if (Regex.IsMatch(content, @"^\d{8,16}$")) return true; // 只允许base64编码的加密数据(需后端验证) if (content.Length % 4 == 0 && Regex.IsMatch(content, @"^[A-Za-z0-9+/]*={0,2}$")) return true; return false; } private static bool IsDomainWhitelisted(string host) => new[] { "yourcompany.com", "api.yourapp.io" }.Contains(host);

这个校验必须放在Zxing解码之后、业务逻辑之前,且不能只在客户端做——客户端校验只是防君子,后端必须二次验证。

5.3 日志与监控:当线上用户说“扫不出来”时,你该看什么

别等用户反馈才排查。我在所有识别入口加了结构化日志:

Debug.Log($"[QR_SCAN] Frame:{frameCount} | Size:{width}x{height} | Brightness:{avgBrightness:F1} | Contrast:{contrast:F1} | Result:{result?.Text ?? "FAIL"}");

其中avgBrightness和contrast是实时计算的:

float avgBrightness = grayscaleBuffer.Average(b => b) / 255f; // 0.0~1.0 float contrast = grayscaleBuffer.Max() - grayscaleBuffer.Min(); // 0~255

上线后,通过分析日志发现:当avgBrightness < 0.2(极暗)或contrast < 30(严重过曝)时,识别失败率>95%。于是加了自动提示:“光线太暗,请打开闪光灯”或“请避开强光直射”。

最后分享一个真实案例:某展会AR导览App上线首日,后台日志显示iOS设备失败率突增到40%。查日志发现失败帧的contrast值普遍>240,而安卓设备都在180以下。立刻意识到是iPhone 14 Pro的“光子引擎”自动提亮导致过曝。解决方案是在iOS端加曝光补偿:

#if UNITY_IOS if (webCamTexture is WebCamTexture iosCam) { iosCam.exposureCompensation = -1.0f; // 强制减一档曝光 } #endif

两小时后失败率回落至5%。这件事让我彻底明白:在Unity里做二维码,70%的功夫不在Zxing,而在理解每一台设备的摄像头脾气。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 8:51:34

RIP路由协议从原理到抓包实验:跳数、计时器与防环机制全解析

做网络这一行&#xff0c;早晚都会碰见RIP。这个距离矢量路由协议在OSPF、BGP这些“现代选手”面前显得老派&#xff0c;但它在路由学习路径里的地位很特殊&#xff1a;原理简单、报文结构直观、实验环境搭建门槛低&#xff0c;非常适合用来理解“路由信息到底是怎么在网络里传…

作者头像 李华
网站建设 2026/10/17 8:51:09

企业级周边游平台管理系统:SpringBoot+Vue前后端分离实战解析

1. 项目定位与整体设计思路1.1 这个系统到底解决什么问题我拿到这个项目的时候&#xff0c;第一反应是&#xff1a;周边游平台听着不大&#xff0c;但真要落地上线&#xff0c;牵涉的角色和流程一点都不少。景区、旅行社、地接、游客、平台运营方&#xff0c;哪一环掉了都会影响…

作者头像 李华
网站建设 2026/10/17 8:51:07

有什么工具能把图片一键转成拼豆图纸?5 类方案盘点与推荐

为什么要用工具转拼豆图纸 拼豆图纸是把图片转成 “每格一种颜色” 的网格&#xff0c;并标注色号与用豆量。人工逐格像素化、对色号、数豆量&#xff0c;耗时长、易出错&#xff0c;新手往往因此放弃个性化创作&#xff0c;所以需要工具辅助。5 类方案对比方案代表优点局限适合…

作者头像 李华
网站建设 2026/10/17 8:51:07

代码不值钱,值钱的是“为什么这么写”

我干了十几年开发&#xff0c;见过太多“能跑就行”的代码&#xff0c;也见过不少让我眼前一亮的写法。最深的体会是&#xff1a;一个功能&#xff0c;三天能写完和一天能写完的人&#xff0c;工资可能差不了多少&#xff1b;但一个功能&#xff0c;写完三个月后没有人敢碰&…

作者头像 李华
网站建设 2026/10/17 8:50:54

从 VS Code 到 IAE:AI辅助开发工作流迁移实录

“我连 VS Code 都想删了”——这个念头第一次冒出来&#xff0c;是在一次连续三小时的 AI 辅助重构之后。说实话&#xff0c;VS Code 本身没什么大毛病&#xff0c;它只是在我花了大量时间配插件、调主题、管理远程连接之后&#xff0c;仍然只能做到“帮我写代码”&#xff0c…

作者头像 李华
网站建设 2026/10/17 8:50:53

做市策略研究:从最优报价模型到强化学习与多智能体仿真

做市策略研究这些年&#xff0c;我经常被人问到一个问题&#xff1a;做市商的报价到底是拍脑袋还是有公式可依&#xff1f;更具体一点&#xff1a;手上库存一多、波动率一上来&#xff0c;买价和卖价到底该挂在哪里&#xff0c;才不会一边被对手单打穿、一边把所有利润变成浮亏…

作者头像 李华