"""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