CSV Application Overview:
Now that you know how to read and write csv files, you will learn a complex and more practical use for these methods.
What data is Logged?:The headers will be the dictionary keys.
self.log_data = {'EntryTime': '', 'ExitTime': '', 'EntryPrice': '', 'ExitPrice': '', 'Symbol': self.symbol, 'Profit': ''}
The body will be the data value for each header key.
- The header is created by concatenating (adding together) the dictionary keys.
- The header and the values are comma separated (CSV).
- Each of the keys have unique values for every symbol.
- Each row contains data from a different symbol.
Advanced write_file Aplication MoveBy Example with logging added.
# Copyright Cloudquant, LLC. All right reserved.
from cloudquant.interfaces import Strategy
import ktgfunc
class LogTradeData(Strategy):
@classmethod
def is_symbol_qualified(cls, symbol, md, service, account):
# American Airlines, Walmart, Microsoft, Target
return symbol in ["AAL", 'WMT', 'MSFT', 'TGT']
@classmethod
def on_strategy_start(cls, md, service, account):
# initialize a variable that will hold the log information
# a list of rows of data
cls.full_log = []
# string variable for the top line of the csv that will be created
cls.headers = ''
def on_start(self, md, order, service, account):
self.log_data = {'EntryTime': '', 'ExitTime': '', 'EntryPrice': '', 'ExitPrice': '', 'Symbol': self.symbol, 'Profit': ''}
#print symbol and timestamp
print(self.symbol + "\n"+ service.time_to_string(service.system_time) + "\tin on start\n")
# create an object of the MoveBy class
# set Initial Value to the previous close
# IsIncrease is True when looking for the price to rise
# MoveByValue is how much you want the price to move by.
# Setting it to .2 means the target price is 20 cents above the prev_close
# Set IsPercent to false when MoveByValue is not a percent
self.entry_condition= ktgfunc.MoveBy(InitialValue=md.stat.prev_close,IsIncrease=True, MoveByValue=.2, IsPercent=False)
# initialize exit condition
self.exit_condition = None
# use self.entry_condition.TargetValue to access the attribute for a print statement
print(self.symbol + " closed at " + str(md.stat.prev_close) + " yeserday.\nIf the price rises $0.20 to " + str(self.entry_condition.TargetValue) + ", a position will be entered")
# create variable used to determine if in position.
self.in_position=False
# variable to track when the strategy is done
self.complete = False
def on_minute_bar(self, event, md, order, service, account, bar):
if self.complete:
service.terminate()
return
# on every bar the MoveBy attributes will be updated
self.entry_condition.Calculate(md.L1.last)
# update calculation if exit_condition has been created
if self.exit_condition is not None:
self.exit_condition.Calculate(md.L1.last)
# buy if the stock has risen more than 20 cents, surpassing the target price
# self.entry_condition.Distance() will return a negative value when it passes the target price
if self.in_position is not True and self.entry_condition.Distance < 0:
print '\n', service.time_to_string(event.timestamp)[11:19] + '\tin on_minute_bar'
print 'Target price:', self.entry_condition.TargetValue, '\tLast Price:', md.L1.last
print'[BUY]\t' + self.symbol +"'s price has increased more than $0.20 from the previous close. A buy order has been sent."
#buy order
order.algo_buy(self.symbol, "market", intent="init", order_quantity=100)
# adjust variable to reflect current position
self.in_position = True
# return so that the below code is note executed until the next on_minute_bar
return
# if in a position, but exit_condition hasn't been set yet:
if self.in_position and self.exit_condition is None:
# set the values for the log data
self.log_data['EntryPrice'] = account[self.symbol].position.entry_price
# executions[0][5]; [0] is the first execution (first trade) [5] is the time
self.log_data['EntryTime'] = account[self.symbol].executions[0][4]
# create an object of the MoveBy class to exit a position
# Setting it to .2 means the target price is 20 cents above the prev_close
self.exit_condition = ktgfunc.MoveBy(InitialValue=account[self.symbol].position.entry_price, IsIncrease=True, MoveByValue=.3, IsPercent=False)
print '\n\n', service.time_to_string(event.timestamp)[11:19] + '\tin on_minute_bar'
print("Your position in " + self.symbol + " was entered at the price: " + str(
account[self.symbol].position.entry_price) + ". \nIf the price rises $0.30 to " + str(
self.exit_condition.TargetValue) + " or the price drops $0.50, the shares will be sold")
# check that exit_condition has been created
# sell if the stock has reached or passed the target price
# which would mean the distance would be negative
if self.exit_condition is not None and self.exit_condition.Distance <= 0:
# set exit log information
self.log_data['ExitTime'] = event.timestamp
# sell order
order.algo_sell(self.symbol, "market", intent="exit")
print '\n\n', service.time_to_string(event.timestamp)[11:19] + '\tin on_minute_bar'
print 'Target price:', self.exit_condition.TargetValue, '\tLast Price:', md.L1.last
print "\n\n[SELL]\t" + self.symbol + " moved up at least 30 cents. A sell order has been sent"
self.complete = True
# check that exit_condition has been created
# sell if the stock drops at least 20 cents from the purchase price.
# meaning the distance from the target value would be above $0.50 from from +0.20
elif self.exit_condition is not None and self.exit_condition.Distance > .5:
# set exit log information
self.log_data['ExitTime'] = event.timestamp
# sell order
order.algo_sell(self.symbol, "market", intent="exit")
print '\n\n', service.time_to_string(event.timestamp)[11:19] + '\tin on_minute_bar'
print 'Target price:', self.exit_condition.TargetValue, '\tLast Price:', md.L1.last
print'[SELL]\t', self.symbol + "'s price decreased $0.50 cents from the target price. A sell order has been sent"
self.complete = True
def on_finish(self, md, order, service, account):
# set the profit
self.log_data['Profit'] = account[self.symbol].realized_pl.entry_pl
# set the ExitPrice equal to the most recent execution price
self.log_data['ExitPrice'] = account[self.symbol].executions[-1][3]
header = ''
body = ''
# comma separated headers
for key in sorted(self.log_data):
header += ',' + key
body += ',' + str(self.log_data[key])
if self.__class__.headers == '':
# dont include the leading ','
self.__class__.headers = header[1:]
# append the row of data to the full log
# dont include the leading ','
self.__class__.full_log.append(body[1:])
@classmethod
def on_strategy_finish(cls, md, service, account):
# create a string of the rows of data
body = ''
for row in cls.full_log:
body += row + '\n'
# write the headers, a newline, and then the body
# overwrite any existing text
service.write_file('TradeInfo', cls.headers + '\n' + body, mode='overwrite')
Console
Note: Not actual console, but the user_data file TradeInfo
EntryPrice,EntryTime,ExitPrice,ExitTime,Profit,Symbol 68.0199966431,1486650905000001,68.3700027466,1486651380315000,35.0006103516,WMT 45.2700004578,1486652345006700,45.6399993896,1486653121291000,36.9998931885,AAL 65.0400009155,1486651025000001,65.3600006104,1486655040556000,31.9999694824,TGT 63.5400009155,1486651445000001,63.8499984741,1486656480869000,30.9997558594,MSFT
In the next lesson, advanced_read, the file written in this example will be read and analyzed.