1. 程式人生 > >我的python回測系統建立之路(1)

我的python回測系統建立之路(1)

        接觸到了不少Python相關的開源專案,也接觸到了不少回測框架,感覺這些框架都比較難懂,加上自己用pandas做回測,效率有點低,要建立一套自己的回測框架。

        讀了不少Python回測框架作者建立框架的思路與理念,覺得使用事件驅動型框架比較好,另外,我要建立的這個框架將會模仿文華財經或者TB進行建立。正好最近讀master Python for finnace 這本書,第九章有講怎麼建立一個回測框架。


          在本文中,將這篇章節的大體思路翻譯成漢語和程式碼,分享給大家。

     +++++++++++++++++++++++++++++++++++++++++++++++++

     翻譯的部分內容

     +++++++++++++++++++++++++++++++++++++++++++++++++

     事件驅動回測系統的概念:

     在真實的交易環境中,一般要包含以下模組:資料,訂單匹配模組,訂單管理,賬戶,更新倉位;

""" Store a single unit of data """
class TickData:
  def __init__(self, symbol, timestamp,
  last_price=0, total_volume=0):
  self.symbol = symbol
  self.timestamp = timestamp
  self.open_price = 0
  self.last_price = last_price
  self.total_volume = total_volume

class MarketData:
  def __init__(self):
      self.__recent_ticks__ = dict()
  def add_last_price(self, time, symbol, price, volume):
      tick_data = TickData(symbol, time, price, volume)
      self.__recent_ticks__[symbol] = tick_data
  def add_open_price(self, time, symbol, price):
      tick_data = self.get_existing_tick_data(symbol, time)
      tick_data.open_price = price
  def get_existing_tick_data(self, symbol, time):
      if not symbol in self.__recent_ticks__:
      tick_data = TickData(symbol, time)
      self.__recent_ticks__[symbol] = tick_data
      return self.__recent_ticks__[symbol]
  def get_last_price(self, symbol):
      return self.__recent_ticks__[symbol].last_price
  def get_open_price(self, symbol):
      return self.__recent_ticks__[symbol].open_price
  def get_timestamp(self, symbol):
      return self.__recent_ticks__[symbol].timestamp
import pandas.io.data as web
""" Download prices from an external data source """
class MarketDataSource:
  def __init__(self):
  	self.event_tick = None
       self.ticker, self.source = None, None
       self.start, self.end = None, None
       self.md = MarketData()
  def start_market_simulation(self):
        data = web.DataReader(self.ticker, self.source,
                              self.start, self.end)
        for time, row in data.iterrows():
        self.md.add_last_price(time, self.ticker,
        row["Close"], row["Volume"])
        self.md.add_open_price(time, self.ticker, row["Open"])
        if not self.event_tick is None:
            self.event_tick(self.md)
class Order:
  def __init__(self, timestamp, symbol, qty, is_buy,is_market_order, price=0):
     self.timestamp = timestamp
     self.symbol = symbol
     self.qty = qty
     self.price = price
     self.is_buy = is_buy
     self.is_market_order = is_market_order
     self.is_filled = False
     self.filled_price = 0
     self.filled_time = None
     self.filled_qty = 0
class Position:
  def __init__(self):
      self.symbol = None
      self.buys, self.sells, self.net = 0, 0, 0
      self.realized_pnl = 0
      self.unrealized_pnl = 0
      self.position_value = 0
  def event_fill(self, timestamp, is_buy, qty, price):
      if is_buy:
         self.buys += qty
      else:
         self.sells += qty
      self.net = self.buys - self.sells
      changed_value = qty * price * (-1 if is_buy else 1)
      self.position_value += changed_value
      if self.net == 0:
         self.realized_pnl = self.position_value
  def update_unrealized_pnl(self, price):
      if self.net == 0:
         self.unrealized_pnl = 0
      else:
         self.unrealized_pnl = price * self.net + \
                                self.position_value
      return self.unrealized_pnl


""" Base strategy for implementation """
class Strategy:
  def __init__(self):
      self.event_sendorder = None
  def event_tick(self, market_data):
      pass
  def event_order(self, order):
      pass
  def event_position(self, positions):
      pass
  def send_market_order(self, symbol, qty, is_buy, timestamp):
      if not self.event_sendorder is None:
         order = Order(timestamp, symbol, qty, is_buy, True)
         self.event_sendorder(order)