2015-02-03 13:33:33 +00:00
|
|
|
import copy
|
2015-05-11 17:30:28 +01:00
|
|
|
from decimal import Decimal, getcontext
|
|
|
|
|
try:
|
|
|
|
|
import Queue as queue
|
|
|
|
|
except ImportError:
|
|
|
|
|
import queue
|
2015-02-03 13:33:33 +00:00
|
|
|
import threading
|
|
|
|
|
import time
|
|
|
|
|
|
2015-04-17 12:34:31 +01:00
|
|
|
from qsforex.execution.execution import OANDAExecutionHandler
|
2015-02-03 13:33:33 +00:00
|
|
|
from qsforex.portfolio.portfolio import Portfolio
|
2015-04-17 12:34:31 +01:00
|
|
|
from qsforex import settings
|
2015-03-06 09:57:15 +00:00
|
|
|
from qsforex.strategy.strategy import TestStrategy
|
2015-04-23 12:45:40 +01:00
|
|
|
from qsforex.data.streaming import StreamingForexPrices
|
2015-02-03 13:33:33 +00:00
|
|
|
|
|
|
|
|
|
2015-04-17 12:34:31 +01:00
|
|
|
def trade(events, strategy, portfolio, execution, heartbeat):
|
2015-02-03 13:33:33 +00:00
|
|
|
"""
|
|
|
|
|
Carries out an infinite while loop that polls the
|
|
|
|
|
events queue and directs each event to either the
|
|
|
|
|
strategy component of the execution handler. The
|
|
|
|
|
loop will then pause for "heartbeat" seconds and
|
|
|
|
|
continue.
|
|
|
|
|
"""
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
|
|
|
|
event = events.get(False)
|
2015-05-11 17:30:28 +01:00
|
|
|
except queue.Empty:
|
2015-02-03 13:33:33 +00:00
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
if event is not None:
|
|
|
|
|
if event.type == 'TICK':
|
|
|
|
|
strategy.calculate_signals(event)
|
2015-05-15 13:50:34 +01:00
|
|
|
portfolio.update_portfolio(event)
|
2015-02-03 13:33:33 +00:00
|
|
|
elif event.type == 'SIGNAL':
|
|
|
|
|
portfolio.execute_signal(event)
|
|
|
|
|
elif event.type == 'ORDER':
|
|
|
|
|
execution.execute_order(event)
|
|
|
|
|
time.sleep(heartbeat)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2015-03-06 09:57:15 +00:00
|
|
|
# Set the number of decimal places to 2
|
|
|
|
|
getcontext().prec = 2
|
|
|
|
|
|
2015-05-27 18:10:55 +01:00
|
|
|
heartbeat = 0.0 # Time in seconds between polling
|
2015-05-11 17:30:28 +01:00
|
|
|
events = queue.Queue()
|
2015-04-17 12:34:31 +01:00
|
|
|
equity = settings.EQUITY
|
2015-02-03 13:33:33 +00:00
|
|
|
|
|
|
|
|
# Trade "Cable"
|
2015-04-23 12:45:40 +01:00
|
|
|
pairs = ["GBPUSD"]
|
2015-02-03 13:33:33 +00:00
|
|
|
|
|
|
|
|
# Create the OANDA market price streaming class
|
|
|
|
|
# making sure to provide authentication commands
|
|
|
|
|
prices = StreamingForexPrices(
|
2015-04-17 12:34:31 +01:00
|
|
|
settings.STREAM_DOMAIN, settings.ACCESS_TOKEN,
|
2015-04-23 12:45:40 +01:00
|
|
|
settings.ACCOUNT_ID, pairs, events
|
2015-02-03 13:33:33 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Create the strategy/signal generator, passing the
|
|
|
|
|
# instrument and the events queue
|
2015-04-23 12:45:40 +01:00
|
|
|
strategy = TestStrategy(pairs, events)
|
2015-02-03 13:33:33 +00:00
|
|
|
|
|
|
|
|
# Create the portfolio object that will be used to
|
|
|
|
|
# compare the OANDA positions with the local, to
|
|
|
|
|
# ensure backtesting integrity.
|
2015-05-15 13:50:34 +01:00
|
|
|
portfolio = Portfolio(
|
|
|
|
|
prices, events, equity=equity, backtest=False
|
|
|
|
|
)
|
2015-02-03 13:33:33 +00:00
|
|
|
|
|
|
|
|
# Create the execution handler making sure to
|
|
|
|
|
# provide authentication commands
|
2015-04-17 12:34:31 +01:00
|
|
|
execution = OANDAExecutionHandler(
|
|
|
|
|
settings.API_DOMAIN,
|
|
|
|
|
settings.ACCESS_TOKEN,
|
|
|
|
|
settings.ACCOUNT_ID
|
|
|
|
|
)
|
2015-02-03 13:33:33 +00:00
|
|
|
|
|
|
|
|
# Create two separate threads: One for the trading loop
|
|
|
|
|
# and another for the market price streaming class
|
|
|
|
|
trade_thread = threading.Thread(
|
|
|
|
|
target=trade, args=(
|
2015-04-17 12:34:31 +01:00
|
|
|
events, strategy, portfolio, execution, heartbeat
|
2015-02-03 13:33:33 +00:00
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
price_thread = threading.Thread(target=prices.stream_to_queue, args=[])
|
|
|
|
|
|
|
|
|
|
# Start both threads
|
|
|
|
|
trade_thread.start()
|
2015-05-11 17:30:28 +01:00
|
|
|
price_thread.start()
|