gs-quant 仓位集合定价:深入解析 PositionSet.price 的实现原理与三种定价策略
【免费下载链接】gs-quantPython toolkit for quantitative finance项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant
gs-quant 的PositionSet.price是仓位集合(Position Set)从"头寸描述"走向"可交易/可分析形态"的核心入口:它将一组以数量(quantity)、权重(weight)或名义敞口(notional)表达的仓位,结合指定日期的市场价格,转换为完整的数量、权重与名义敞口信息。本文以该方法的 API 文档与源码实现为骨架,讲解其全部参数语义、三种加权策略的自动推断规则、底层定价请求的构造过程,以及长空(long/short)组合、未定价仓位等边界场景的处理方式,读者读完后可以熟练完成"构造仓位集合 → 解析标识符 → 定价 → 提取结果"的完整工作流。
PositionSet.price 在仓位集合生命周期中的位置
在 gs-quant 中,PositionSet用于持有与某一特定日期(date)关联的一组仓位(position_set.py)。一个典型的仓位集合使用流程包含三个步骤:
- 构造:用
Position对象或from_list/from_dicts/from_frame等类方法构建仓位集合,此时仓位通常只有标识符(如'AAPL UW')与部分数量/权重信息; - 解析(resolve):调用 resolve() 将 Bloomberg 标识符等解析为 Marquee 资产 ID(
asset_id),未解析成功的仓位会被放入unresolved_positions; - 定价(price):调用
price()请求定价 API,回填每个仓位的quantity、weight、notional与hard_to_borrow(难借券标志),未返回价格的仓位进入unpriced_positions。
price()的 docstring 将其用途概括为:"Fetch positions weights from quantities, or vice versa"(从数量求权重,或反向从权重求数量)。这意味着无论你手头拥有的是数量、权重还是名义敞口,定价后都能补齐其余两个维度,从而得到一份完整的仓位快照。
参数详解
PositionSet.price的方法签名为(position_set.py):
def price( self, currency: Optional[Currency] = Currency.USD, use_unadjusted_close_price: bool = True, weighting_strategy: Optional[PositionSetWeightingStrategy] = None, handle_long_short: bool = False, fail_on_unpriced_positions: bool = False, **kwargs, )| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
currency | Currency | Currency.USD | 参考名义(reference notional)的计价货币,不传时默认美元 |
use_unadjusted_close_price | bool | True | 使用未复权收盘价(unadjusted close price)还是复权价,默认未复权 |
weighting_strategy | PositionSetWeightingStrategy | None | 定价加权策略:Quantity、Weight或Notional;为None时根据仓位信息自动推断 |
handle_long_short | bool | False | 是否处理长空组合。由于按总名义(gross notional)定价会丢失方向性,置为True可将返回的总权重转换为带符号的参考权重,同时把仓位集合的参考名义设为总名义 |
fail_on_unpriced_positions | bool | False | 定价后若存在未定价仓位,是否直接抛出异常 |
**kwargs | — | — | 透传给定价 API 的额外参数,例如dataset、fractional_shares等 |
其中PositionSetWeightingStrategy在 gs_quant/common.py 中定义,取值对应三种定价输入模式:Quantity(按数量)、Weight(按权重)、Notional(按名义敞口)。
三种定价模式与默认策略的自动推断
price()的第一步是根据仓位数据推断加权策略。静态方法 __get_default_weighting_strategy 的推断逻辑为:
- 若显式传入了
weighting_strategy,直接采用; - 否则检查所有仓位的
weight、quantity、notional缺失情况:- 若所有仓位都有
weight,且指定了reference_notional或存在缺quantity的仓位,则选择Weight; - 若所有仓位都有
notional,则选择Notional; - 其余情况选择
Quantity; - 若三种字段均有缺失而无法推断,抛出
MqValueError。
- 若所有仓位都有
推断完成后还会做一致性校验:选择的策略所依赖的字段必须齐全(例如选Weight则所有仓位必须有weight),且按权重定价必须显式指定reference_notional,否则抛出MqValueError(源码中明确写入'You must specify a reference notional in order to price by weight.')。
在确定策略后,__convert_positions_for_pricing 将仓位转换为 API 输入PositionPriceInput:按Weight策略只传weight,按Notional只传notional,按Quantity只传quantity;若某仓位缺少asset_id则报错提示先 resolve 或移除未映射标识符。
实战示例:从三种输入出发定价
以下三个示例完整继承自方法 docstring,并补充了前置的resolve()调用(注意示例中均先解析标识符、再定价):
从数量(quantity)求权重:
import datetime as dt from gs_quant.markets.position_set import Position, PositionSet, PositionSetWeightingStrategy my_positions = [Position(identifier='AAPL UW', quantity=100), Position(identifier='MSFT UW', quantity=100)] position_set = PositionSet(positions=my_positions, date=dt.date(2023, 3, 16)) position_set.resolve() position_set.price(weighting_strategy=PositionSetWeightingStrategy.Quantity)从权重(weight)求数量(需指定 reference_notional):
import datetime as dt from gs_quant.markets.position_set import Position, PositionSet, PositionSetWeightingStrategy my_positions = [Position(identifier='AAPL UW', weight=0.5), Position(identifier='MSFT UW', weight=0.5)] position_set = PositionSet(positions=my_positions, date=dt.date(2023, 3, 16), reference_notional=10000000) position_set.resolve() position_set.price(weighting_strategy=PositionSetWeightingStrategy.Weight)从名义敞口(notional)求权重与数量:
import datetime as dt from gs_quant.markets.position_set import Position, PositionSet, PositionSetWeightingStrategy my_positions = [Position(identifier='AAPL UW', notional=10000), Position(identifier='MSFT UW', notional=10000)] position_set = PositionSet(positions=my_positions, date=dt.date(2023, 3, 16)) position_set.resolve() position_set.price(weighting_strategy=PositionSetWeightingStrategy.Notional)定价完成后,可用 get_positions() 以 DataFrame 形式查看每个仓位的quantity、weight、notional等字段。
底层原理:定价请求的构造与结果回填
price()的核心实现位于 position_set.py,可拆解为四个阶段:
1. 构造PriceParameters。方法将推断出的加权策略连同仓位集合属性打包为一个请求参数对象(price.py):
price_parameters = PriceParameters( currency=currency, divisor=self.divisor, frequency=MarketDataFrequency.End_Of_Day, target_notional=self.reference_notional, notional_type='Gross', pricing_date=self.date, price_regardless_of_assets_missing_prices=True, weighting_strategy=weighting_strategy, use_unadjusted_close_price=use_unadjusted_close_price, fractional_shares=should_allow_fractional_shares, )注意几个值得关注的默认行为:notional_type='Gross'(按总名义口径计算权重)、price_regardless_of_assets_missing_prices=True(即使部分资产缺价格也继续定价)、frequency默认为日频End_Of_Day。
2. 处理 kwargs 透传。若传入dataset键,则将其映射为asset_data_set_id并清空frequency(表示改用自定义数据集定价);其余 kwargs 逐项setattr到PriceParameters上。fractional_shares(是否允许小数股)也是通过 kwargs 控制的:未显式传入时,仅Notional策略默认允许小数股。PriceParameters还支持vendor、fallback_date、measures、initial_price等字段,均可通过 kwargs 覆盖。
3. 调用定价 API。方法通过GsPriceApi.price_positions提交PositionSetPriceInput(positions=..., parameters=...)请求(gs_quant/api/gs/price.py),响应中的每个仓位由PositionPriceResponse承载(price.py),包含quantity、weight、notional、spot、fx_spot、multiplier、hard_to_borrow等丰富字段。
4. 回填与归类。方法按asset_id + 标签哈希(由 __hash_position_tag_list 拼接tag.name + '-' + tag.value生成)把响应映射回本地仓位,逐仓回填quantity、weight、notional与hard_to_borrow,并更新self.positions;未出现在响应中的仓位放入self.__unpriced_positions。
长空组合与未定价仓位的边界处理
长空组合(long/short):当输入仓位集合是多空组合时,按总名义定价会使权重丧失方向性(多空互相抵消)。开启handle_long_short=True后,源码使用math.copysign(w, pos.notional)依据每个仓位的名义方向恢复权重的正负号(position_set.py),同时将reference_notional更新为 API 返回的gross_notional(总名义),从而保留组合的方向信息。
未定价仓位:默认情况下未定价仓位会被静默移入unpriced_positions,可通过 get_unpriced_positions() 以 DataFrame 查看、用 remove_unpriced_positions() 移除。若希望定价失败时立即报错,设置fail_on_unpriced_positions=True,此时会抛出包含未定价仓位标识符与日期信息的MqValueError,便于排查数据源缺失。
与配套方法的协同使用
price()的 docstring 在 "See also" 中列出了三个配套方法,它们构成完整的仓位集合处理闭环:
- get_unpriced_positions:查看本次定价未成功的仓位(DataFrame);
- get_unresolved_positions:查看
resolve()阶段未能映射到资产 ID 的仓位; - resolve:将
identifier(如'AAPL UW')解析为 Marquee 资产 ID,是price()的前置步骤——若仓位缺少asset_id,定价会在__convert_positions_for_pricing阶段直接报错。
此外,对于需要批量定价的场景,PositionSet还提供了类方法 price_many 用于一次性为多个仓位集合定价,其 API 文档见 PositionSet.price_many.rst,适合组合规模较大时的批量处理。
小结
PositionSet.price是 gs-quant 仓位集合模块中最常用的方法之一:它通过currency、use_unadjusted_close_price、weighting_strategy、handle_long_short、fail_on_unpriced_positions等参数覆盖了从普通组合到长空组合、从数量到权重再到名义敞口的各类定价诉求,并通过 kwargs 提供了对定价 API 参数的细粒度透传。理解其默认策略推断逻辑与PriceParameters的构造过程,能够帮助使用者写出更精准、更符合预期的定价调用——例如按权重定价务必携带reference_notional、多空组合务必开启handle_long_short。相关源码与文档见 position_set.py、target/price.py 与 PositionSet.price 文档。
【免费下载链接】gs-quantPython toolkit for quantitative finance项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考