统一单入口 Go 工程与前端依赖目录,增加后台供应商配置、候选审核、计划预算、成交冲正、持仓复盘和站内通知。接入策略版本、Python 回测、可配置 A 股公开行情及 zap 文件轮转日志,补充迁移、契约与验证。
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import sys, json
|
||||
from decimal import Decimal
|
||||
|
||||
def cents(value):
|
||||
n = Decimal(value) * 100
|
||||
if n != n.to_integral_value() or n <= 0:
|
||||
raise ValueError('invalid price')
|
||||
return int(n)
|
||||
|
||||
def money(value):
|
||||
return ('-' if value < 0 else '') + str(abs(value)//100) + '.' + str(abs(value)%100).zfill(2)
|
||||
|
||||
def run(data):
|
||||
p = data['parameters']
|
||||
bars = data['bars']
|
||||
cash = int(Decimal(data['initial_cash'])*100)
|
||||
initial = cash
|
||||
quantity, cost, peak, drawdown, previous = 0, 0, cash, 0, False
|
||||
trades, equity = [], []
|
||||
closes = [cents(b['close']) for b in bars]
|
||||
for i, bar in enumerate(bars):
|
||||
# Only preceding completed bars generate a signal. Execute at next open.
|
||||
if i >= p['long_window']:
|
||||
short = sum(closes[i-p['short_window']:i]) * p['long_window']
|
||||
long = sum(closes[i-p['long_window']:i]) * p['short_window']
|
||||
bullish = short > long
|
||||
open_price = cents(bar['open'])
|
||||
if bullish and not previous and quantity == 0:
|
||||
price = (open_price*(10000+p['slippage_bps'])+9999)//10000
|
||||
unit = p['lot_size']
|
||||
units = cash*10000//(price*unit*(10000+p['fee_bps']))
|
||||
quantity = units*unit
|
||||
gross = quantity*price
|
||||
fee = (gross*p['fee_bps']+9999)//10000
|
||||
if quantity:
|
||||
cash -= gross+fee
|
||||
cost = gross+fee
|
||||
trades.append({'date':bar['date'],'side':'BUY','quantity':str(quantity),'price':money(price),'fee':money(fee),'realized_pnl':None})
|
||||
elif not bullish and previous and quantity:
|
||||
price = max(1,open_price*(10000-p['slippage_bps'])//10000)
|
||||
gross = quantity*price
|
||||
fee = (gross*p['fee_bps']+9999)//10000
|
||||
cash += gross-fee
|
||||
trades.append({'date':bar['date'],'side':'SELL','quantity':str(quantity),'price':money(price),'fee':money(fee),'realized_pnl':money(gross-fee-cost)})
|
||||
quantity, cost = 0, 0
|
||||
previous = bullish
|
||||
value = cash+quantity*closes[i]
|
||||
peak = max(peak,value)
|
||||
drawdown = max(drawdown,(peak-value)*10000//peak)
|
||||
equity.append({'date':bar['date'],'equity':money(value)})
|
||||
final = cash+quantity*closes[-1]
|
||||
return {'engine_version':'sma_cross_v1','final_equity':money(final),'cash':money(cash),'remaining_quantity':str(quantity),'total_return_bps':(final-initial)*10000//initial,'max_drawdown_bps':drawdown,'trades':trades,'equity_curve':equity,'valuation':'Final close valuation; open positions are not liquidated.'}
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(json.dumps(run(json.load(sys.stdin)),separators=(',',':')))
|
||||
Reference in New Issue
Block a user