Skip to content

Commit

Permalink
Merge pull request #62 from Ferev/twap_strategy
Browse files Browse the repository at this point in the history
added twap strategy, updated config strategy args parsing
  • Loading branch information
timkpaine committed Jul 29, 2020
2 parents 647d1a6 + abdf173 commit 338232a
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 4 deletions.
8 changes: 6 additions & 2 deletions aat/config/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ def _config_to_dict(filename: str) -> Dict[str, Dict[str, Union[str, List[str],
def getStrategies(strategies: List) -> List:
strategy_instances = []
for strategy in strategies:
mod, clazz_and_args = strategy.split(':')
clazz, args = clazz_and_args.split(',') if ',' in clazz_and_args else clazz_and_args, ()
if type(strategy) == list:
mod, clazz = strategy[0].split(':')
args = strategy[1:]
else:
mod, clazz = strategy.split(':')
args = ()
mod = importlib.import_module(mod)
clazz = getattr(mod, clazz)
strategy_instances.append(clazz(*args))
Expand Down
87 changes: 87 additions & 0 deletions aat/strategy/sample/twap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from aat import Strategy, Event, Order, Trade, Side
from datetime import datetime, timedelta


class TimeWeightedAveragePrice(Strategy):
def __init__(self, *args, **kwargs) -> None:
'''Time Weighted Average Price Strategy
Arguments:
delay (int): time delay between orders
target_volume (int): volume to be processed
step (int): volume to process at each order
start_time (str): time to start execution, converted to datetime
end_time_offset (int): number of seconds past start_time to end orders after
side (str): Buy/Sell side
price_limit (int): price limit above trade price
'''
super(TimeWeightedAveragePrice, self).__init__()
self.delay = int(args[0])
self.target_volume = int(args[1])
self.step = int(args[2])
self.start_time = datetime.now() if args[3] == 'now' \
else datetime.strptime(args[3], '%Y-%m-%d %H:%M:%S.%f')
self.end_time = self.start_time + timedelta(seconds=int(args[4]))
self.side = Side.BUY if args[5].lower() == 'buy' else Side.SELL
self.price_limit = int(args[6])
self.target_time = self.start_time
self.volume_processed = 0
self.volume_ordered = 0

async def onStart(self, event: Event) -> None:
self.subscribe(self.instruments()[0])

async def onTrade(self, event: Event) -> None:
'''Called whenever a `Trade` event is received'''
trade: Trade = event.target # type: ignore
if self.volume_ordered < self.target_volume:
now = datetime.now()
if now >= self.target_time and now < self.end_time:
req = Order(side=Side.BUY,
price=trade.price + self.price_limit,
volume=self.step,
instrument=trade.instrument,
order_type=Order.Types.MARKET,
exchange=trade.exchange)

print("requesting : {}".format(req))
self.target_time += timedelta(seconds=self.delay)
self.volume_ordered += self.step
await self.newOrder(req)
else:
print("Waiting for time window")
else:
print("Orders launched, do nothing! vol: {}".format(self.volume_processed))

async def onBought(self, event: Event) -> None:
trade: Trade = event.target # type: ignore
print('bought {:.2f} @ {:.2f}'.format(trade.volume, trade.price))
self.volume_processed += trade.volume
print('processed vol: {}'.format(self.volume_processed))

async def onSold(self, event: Event) -> None:
trade: Trade = event.target # type: ignore
print('bought {:.2f} @ {:.2f}'.format(trade.volume, trade.price))
self.volume_processed += trade.volume
print('processed vol: {}'.format(self.volume_processed))

async def onReject(self, event: Event) -> None:
print('order rejected')
trade: Trade = event.target # type: ignore
self.volume_ordered -= trade.volume
import sys
sys.exit(0)

def slippage(self, trade: Trade) -> Trade:
# trade.slippage = trade.price * .0001 # .01% price impact TODO
return trade

def transactionCost(self, trade: Trade) -> Trade:
# trade.transactionCost = trade.price * trade.volume * .0025 # 0.0025 max fee TODO
return trade

async def onExit(self, event: Event) -> None:
print('Finishing...')
import matplotlib.pyplot as plt # type: ignore
plt.plot(self.positions()[0].unrealizedPnlHistory)
plt.show()
4 changes: 2 additions & 2 deletions config/synthetic.cfg
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[general]
verbose=0
api=0
trading_type=backtest
trading_type=simulation

[exchange]
exchanges=
aat.exchange:SyntheticExchange

[strategy]
strategies =
aat.strategy.sample.buy_and_hold:BuyAndHoldStrategy
aat.strategy.sample.twap:TimeWeightedAveragePrice,5,1000,100,now,60,buy,10

[risk]
max_drawdown = 100.0
Expand Down

0 comments on commit 338232a

Please sign in to comment.