92 lines
2.4 KiB
Python
92 lines
2.4 KiB
Python
"""PositionLedger 单标的持仓对象测试(raw 计均价、T+1 冻结)。"""
|
||
import pytest
|
||
|
||
from sanguo_trader.position_ledger import PositionLedger
|
||
|
||
|
||
def test_new_position_empty():
|
||
p = PositionLedger(symbol="600000")
|
||
assert p.volume == 0
|
||
assert p.frozen == 0
|
||
assert p.avg_price == 0.0
|
||
assert p.available == 0
|
||
|
||
|
||
def test_buy_sets_avg_price_and_freezes():
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(price=10.0, volume=100)
|
||
assert p.volume == 100
|
||
assert p.frozen == 100 # T+1:买入当日冻结
|
||
assert p.available == 0 # 当日不可卖
|
||
assert p.avg_price == 10.0
|
||
|
||
|
||
def test_avg_price_weighted_on_add():
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 100)
|
||
p.unfreeze() # 次日解冻
|
||
p.apply_buy(12.0, 100)
|
||
assert p.avg_price == 11.0 # (10*100 + 12*100)/200
|
||
assert p.volume == 200
|
||
# 新买的 100 又被冻结(T+1)
|
||
assert p.frozen == 100
|
||
assert p.available == 100
|
||
|
||
|
||
def test_cannot_sell_frozen():
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 100)
|
||
assert p.frozen == 100
|
||
assert p.available == 0 # 当日不可卖
|
||
|
||
|
||
def test_unfreeze_makes_available():
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 100)
|
||
p.unfreeze()
|
||
assert p.frozen == 0
|
||
assert p.available == 100
|
||
|
||
|
||
def test_sell_reduces_volume():
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 200)
|
||
p.unfreeze()
|
||
p.apply_sell(11.0, 100)
|
||
assert p.volume == 100
|
||
assert p.available == 100
|
||
|
||
|
||
def test_sell_odd_lot_allowed():
|
||
"""A 股卖出允许零股(退出持仓的基本操作)。"""
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 200)
|
||
p.unfreeze()
|
||
p.apply_sell(11.0, 50) # 50 股零股
|
||
assert p.volume == 150
|
||
|
||
|
||
def test_sell_over_available_raises():
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 100)
|
||
p.unfreeze()
|
||
with pytest.raises(ValueError, match="available"):
|
||
p.apply_sell(11.0, 200)
|
||
|
||
|
||
def test_sell_frozen_raises():
|
||
"""T+1:当日买入冻结,卖出冻结量必报错。"""
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 100)
|
||
with pytest.raises(ValueError):
|
||
p.apply_sell(11.0, 50)
|
||
|
||
|
||
def test_clear_position_avg_price_resets():
|
||
p = PositionLedger(symbol="600000")
|
||
p.apply_buy(10.0, 100)
|
||
p.unfreeze()
|
||
p.apply_sell(11.0, 100)
|
||
assert p.volume == 0
|
||
assert p.avg_price == 0.0
|