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=(',',':')))