Event-driven backtest/realtime quantitative trading system.
- Raw Data -> DataEvent
DataEvents process raw data and generate events. Raw data can be news, history price, market data, etc. A DataEvent is a numpy array and its first value must be a timestamp. It will be put into a priority queue with the timestamp so all history events for backtesting are ordered by time.
- DataEvent -> Signal (A value from -1 to 1)
Alphas represent trading strategies. An Alpha subscribes to a main_dataevent
and has access to other DataEvents. It is triggered when its main_dataevent
sends out a new data event. It processes data and calculates a signal which is sent to a handler in Portfolio.
- Signals -> Transactions
Portfolio is a combination of Alphas. It opens orders according to the signals received, and then sends them to Connectors. It also holds current positions and a list of Transactions.
- Transaction -> Execute
Connectors are order executors. A Connector could be an API wrapper of an exchange or a simulator using history data.
- Transactions -> Statistics
Statistics are triggered at the end of program. They will collect information from Transactions and save data, generate visual charts, calculate ratios, etc.
Transactions are records that store information through the pipeline. A Transaction is filled by different modules and stored in Portfolio.
EventQueue contains a priority queue and a locking system. DataEvents put events into the EventQueue and wait for its event to be consumed. There will be only one event in EventQueue for every DataEvent, so that all history events are triggered by time.
Manifest is a TOML file that defines the structure of a Portfolio and dependencies of modules.
git clone https://github.com/wynfred/presso.git
cd presso
sudo pip3 install .
presso run example/manifest.toml
# Press ENTER to stop DataEvents and run Statistics
# Check presso.log for logs
python3.6
aiohttp
ccxt
numpy
toml
from presso.core.abstract.alpha import AbstractAlpha
class ExampleAlpha(AbstractAlpha):
def _init(self):
# TODO
pass
async def _calcSignal(self, data):
# TODO
pass
@property
def name(self):
return 'Example'
from presso.core.abstract.dataevent import AbstractDataEvent
class ExampleDataEvent(AbstractDataEvent):
def _init(self):
# TODO
pass
async def _iter(self):
# TODO
pass
from presso.core.abstract.portfolio import AbstractPortfolio
class ExamplePortfolio(AbstractPortfolio):
def _init(self):
# TODO
self._positions[TICKER.USD] = 100000
self._positions[TICKER.BTC] = 0
def onExampleSignal(self, transaction):
# TODO
if transaction.signal > 0 and self._positions[TICKER.USD] > 0:
transaction.buy = TICKER.BTC
transaction.sell = TICKER.USD
transaction.total = self._positions[TICKER.USD] * 0.5
transaction.operation = OPERATION.MARKET
self._execute(self._connectors['kline_history'], transaction)
from presso.core.abstract.connector import AbstractConnector
class ExampleConnector(AbstractConnector):
def _init(self):
# TODO
pass
async def execute(self, transaction):
# TODO
pass
from presso.core.abstract.statistics import AbstractStatistics
class ExampleStatistics(AbstractStatistics):
def _init(self):
# TODO
pass
def onTransaction(self, transaction):
# TODO
pass
def finish(self):
# TODO
pass