Skip to content
This repository was archived by the owner on May 8, 2021. It is now read-only.

Commit 3538881

Browse files
commit
1 parent 0d22e50 commit 3538881

File tree

7 files changed

+175
-61
lines changed

7 files changed

+175
-61
lines changed

back.ipynb

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 5,
6+
"metadata": {},
7+
"outputs": [
8+
{
9+
"name": "stderr",
10+
"output_type": "stream",
11+
"text": [
12+
"Tuesday, October 01, 2019 03:17:53 PM IST INFO: Starting Backtest for ba from 2019-09-24 09:30:00 to 2019-09-24 15:30:00 with initial capital = 100000\n",
13+
"Tuesday, October 01, 2019 03:17:56 PM IST INFO: Received Signals from ba\n"
14+
]
15+
}
16+
],
17+
"source": [
18+
"from libkloudtrader.algorithm import *\n",
19+
"import libkloudtrader.analysis as analysis\n",
20+
"import pandas as pd\n",
21+
"import numpy as np\n",
22+
"\n",
23+
"\n",
24+
"\n",
25+
"def ba(backtest,data):\n",
26+
" '''\n",
27+
" data['high']=data.close.shift(1).rolling(window=5).max()\n",
28+
" data['low']=data.close.shift(1).rolling(window=5).min()\n",
29+
" data['avg']=analysis.ma(data.close,5)\n",
30+
" buy=(data.close>data.high)\n",
31+
" sell=(data.close<data.avg)\n",
32+
" #short=(data.close<data.low)\n",
33+
" #cover=(data.close>data.avg)\n",
34+
" if buy.tail(1).bool():\n",
35+
" backtest.buy(5)\n",
36+
" elif sell.tail(1).bool():\n",
37+
" backtest.sell(5)\n",
38+
"\n",
39+
" '''\n",
40+
" pass\n",
41+
" #rets=analysis.daily_returns(data.close)\n",
42+
" #data['volatility']=analysis.moving_volatility(rets,1)\n",
43+
" #data['slip']=data.high-data.close\n",
44+
" \n",
45+
"\n",
46+
"\n",
47+
" \n",
48+
"\n",
49+
"run_backtest(ba,['AAPL'],data=\"US_STOCKS_ohlcv\",start='2019-09-24 09:30:00',end='2019-09-24 15:30:00',data_interval='15m')"
50+
]
51+
},
52+
{
53+
"cell_type": "code",
54+
"execution_count": null,
55+
"metadata": {},
56+
"outputs": [],
57+
"source": []
58+
}
59+
],
60+
"metadata": {
61+
"kernelspec": {
62+
"display_name": "Python 3",
63+
"language": "python",
64+
"name": "python3"
65+
},
66+
"language_info": {
67+
"codemirror_mode": {
68+
"name": "ipython",
69+
"version": 3
70+
},
71+
"file_extension": ".py",
72+
"mimetype": "text/x-python",
73+
"name": "python",
74+
"nbconvert_exporter": "python",
75+
"pygments_lexer": "ipython3",
76+
"version": "3.7.4"
77+
}
78+
},
79+
"nbformat": 4,
80+
"nbformat_minor": 4
81+
}

back.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
def ba(backtest,data):
9-
'''
9+
1010
data['high']=data.close.shift(1).rolling(window=5).max()
1111
data['low']=data.close.shift(1).rolling(window=5).min()
1212
data['avg']=analysis.ma(data.close,5)
@@ -19,8 +19,7 @@ def ba(backtest,data):
1919
elif sell.tail(1).bool():
2020
backtest.sell(5)
2121

22-
'''
23-
pass
22+
2423
#rets=analysis.daily_returns(data.close)
2524
#data['volatility']=analysis.moving_volatility(rets,1)
2625
#data['slip']=data.high-data.close
@@ -29,4 +28,4 @@ def ba(backtest,data):
2928

3029

3130

32-
run_backtest(ba,['AAPL'],data="US_STOCKS_ohlcv",start_date='2019-01-01',end_date='2019-07-01')
31+
run_backtest(ba,['AAPL'],data="US_STOCKS_times_and_sale",start='2019-09-24 09:30:00',end='2019-09-24 15:30:00',data_interval='15m')

libkloudtrader/algorithm.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,25 @@
2626
def run_backtest(strategy: str,
2727
symbol_bucket: List[str],
2828
data: str,
29-
start_date: Any,
30-
end_date: Any,
29+
start: Any,
30+
end: Any,
31+
data_interval:str="1d",
3132
preferred_price_point: str = 'close',
3233
preferred_benchmark: str = 'SPY',
33-
data_interval: str = '1d',
3434
initial_capital: float = 100000,
3535
commission: float = 0,
3636
slippage=True):
3737
"""Backtester function"""
3838
try:
3939
logger.info(
4040
'Starting Backtest for {} from {} to {} with initial capital = {}'.
41-
format(strategy.__name__, start_date, end_date, initial_capital))
41+
format(strategy.__name__, start, end, initial_capital))
4242
data_to_backtest_on = Data_Types[data].value
4343
for symbol in symbol_bucket:
44-
data_batch = data_to_backtest_on(symbol,
45-
start_date,
46-
end_date
44+
data_batch = data_to_backtest_on(symbol=symbol,
45+
start=start,
46+
end=end,interval=data_interval
4747
)
48-
print(data_batch)
4948
batch = processing.Buffer(len(data_batch), dtype=object)
5049
backtest=bt.Backtest(capital=100000,commission=1,enable_slippage=True)
5150
for datetime, bar in data_batch.iterrows():
@@ -54,14 +53,16 @@ def run_backtest(strategy: str,
5453
data_batch = pd.DataFrame(batch)
5554

5655
locals()['strategy'](backtest,data_batch)
57-
#print(pd.merge(data_batch,backtest.get_portfolio,on = index))
58-
#print(data_batch)
56+
57+
print(backtest.get_trade_log)
58+
del backtest
59+
5960

6061
'''
6162
for symbol in symbol_bucket:
6263
data_batch = data_to_backtest_on(symbol,
63-
start_date,
64-
end_date,
64+
start,
65+
end,
6566
interval=data_interval)
6667
for symbol in symbol_bucket:
6768
@@ -88,7 +89,7 @@ def run_backtest(strategy: str,
8889
#df['positions in '+symbol]=100*df['positions']
8990
#print(bt.trades)
9091

91-
logger.info("Received Signals from {}".format(strategy.__name__))
92+
#logger.info("Received Signals from {}".format(strategy.__name__))
9293

9394
except (KeyboardInterrupt, SystemExit):
9495
print('\n')
@@ -102,8 +103,8 @@ def run_backtest(strategy: str,
102103
raise exception
103104
exit()
104105

105-
#print(return_data_from_enum(a,symbol,start_date, end_date))
106-
#print(locals()[a](symbol, start_date, end_date))
106+
#print(return_data_from_enum(a,symbol,start, end))
107+
#print(locals()[a](symbol, start, end))
107108

108109

109110
def run_live(strategy: str,

libkloudtrader/backtest.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,28 @@ def __init__(self,capital:float,commission:float,enable_slippage:bool):
4444
self.position=0
4545
self.commission=commission
4646
self.enable_slippage=enable_slippage
47-
self.slippage=0
47+
self.slippage=0.0
48+
self.asset_price=0.0
4849
self.trades_log=pd.DataFrame(columns=['datetime','trade_type','price','fill_price','order_cost','capital','position'])
4950

5051

5152
def buy(self,quantity):
5253
'''emulates a buy order'''
5354
self.capital-=self.order_cost
5455
self.update_positions(quantity)
55-
self.update_trade_logs(datetime=self.bar.datetime,trade_type='Buy',price=self.bar.close,fill_price=self.fill_price,order_cost=self.order_cost,capital=self.capital,position=self.position)
56+
self.update_trade_logs(datetime=self.bar.datetime,trade_type='Buy',price=self.asset_price,fill_price=self.fill_price,order_cost=self.order_cost,capital=self.capital,position=self.position)
5657
#print('Bought {} of stocks @ {} but price is {}'.format(quantity,self.order_cost,self.bar.close))
5758

5859

5960
def sell(self,quantity):
6061
'''emulates a sell order'''
61-
#if self.position!=0:
62-
self.capital+=self.order_cost
63-
self.update_positions(-1*quantity)
64-
self.update_trade_logs(datetime=self.bar.datetime,trade_type='Sell',price=self.bar.close,fill_price=self.fill_price,order_cost=self.order_cost,capital=self.capital,position=self.position)
62+
if self.position!=0:
63+
self.capital+=self.order_cost
64+
self.update_positions(-1*quantity)
65+
self.update_trade_logs(datetime=self.bar.datetime,trade_type='Sell',price=self.asset_price,fill_price=self.fill_price,order_cost=self.order_cost,capital=self.capital,position=self.position)
6566
#print('Sold {} of stocks @ {} but price is {}'.format(quantity,self.order_cost,self.bar.close))
66-
#else:
67-
#pass#print('No position to close')
67+
else:
68+
print('No position to close')
6869

6970
def update_trade_logs(self,datetime,trade_type,price,fill_price,order_cost,capital,position):
7071
df=pd.DataFrame([{'datetime':datetime,'trade_type':trade_type,'price':price,'fill_price':fill_price,'order_cost':order_cost,'capital':capital,'position':position}])
@@ -79,29 +80,30 @@ def get_trade_log(self):
7980
def update_bar(self,index,bar):
8081
self.bar=bar
8182
self.bar.datetime=index
83+
if 'price' in self.bar:
84+
self.asset_price=self.bar.price
85+
else:
86+
self.asset_price=self.bar.close
8287

8388
def update_positions(self,quantity):
8489
self.position+=quantity
8590

8691
@property
8792
def calculate_commission(self):
88-
commiss=(self.commission/100)*self.bar.close
89-
return commiss
93+
return (self.commission/100)*self.fill_price
94+
9095

9196
@property
9297
def calculate_slippage(self):
9398
'''how is slippage calculated?'''
9499
'''slippage should not be more than 2% in most of the trades. so we generate a random percentage b/w 0-2.use that number as %age'''
95100
if self.enable_slippage:
96-
slippage_percent= np.random.uniform(low=0, high=0.02)
97-
slippage=slippage_percent*self.bar.close
98-
return slippage
101+
return np.random.uniform(low=0, high=0.02)*self.asset_price
99102
return 0.0
100103

101104
@property
102105
def fill_price(self):
103-
return self.bar.close+self.calculate_slippage
104-
106+
return self.asset_price+self.calculate_slippage
105107

106108
@property
107109
def order_cost(self):

libkloudtrader/enumerables.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
class Data_Types(Enum):
99
'''Data Types of backtesting and live trading'''
1010
US_STOCKS_ohlcv = partial(stocks.ohlcv)
11+
US_STOCKS_times_and_sale=partial(stocks.time_and_sale)
12+
CRYPTO_ohlcv=partial(crypto.ohlcv)
1113
US_STOCKS_live_feed = partial(stocks.incoming_tick_data_handler)
1214
CRYPTO_live_feed = partial(crypto.incoming_tick_data_handler)
1315
CRYPTO_live_feed_level2 = partial(crypto.incoming_tick_data_handler_level2)

libkloudtrader/stocks.py

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -493,41 +493,17 @@ def ohlcv(symbol: str,
493493
else:
494494
logger.error('Oops! An error Occurred ⚠️')
495495
raise InvalidBrokerage
496-
if interval not in ("1d", "1w", "1M", "1m", "5m", "15m"):
496+
if interval not in ("1d", "1w", "1M"):
497497
logger.error('Oops! An error Occurred ⚠️')
498498
raise InvlaidTimeInterval(
499-
'Invalid Time Interval. Available time intervals for this function are: "1d","1w","1M","1m","5m","15m" '
499+
'Invalid Time Interval. Available time intervals for this function are: "1d","1w","1M"'
500500
)
501501
if interval == "1d":
502502
interval = "daily"
503503
elif interval == "1w":
504504
interval = "weekly"
505505
elif interval == "1M":
506506
interval = "monthly"
507-
elif interval == "1m":
508-
return min1_bar_data(symbol=symbol,
509-
start=start,
510-
end=end,
511-
data_filter='open',
512-
brokerage=brokerage,
513-
access_token=access_token,
514-
dataframe=True)
515-
elif interval == "5m":
516-
return min5_bar_data(symbol=symbol,
517-
start=start,
518-
end=end,
519-
data_filter='open',
520-
brokerage=brokerage,
521-
access_token=access_token,
522-
dataframe=True)
523-
elif interval == "15m":
524-
return min15_bar_data(symbol=symbol,
525-
start=start,
526-
end=end,
527-
data_filter='open',
528-
brokerage=brokerage,
529-
access_token=access_token,
530-
dataframe=True)
531507
params: dict = {
532508
"symbol": str(symbol.upper()),
533509
"start": str(start),
@@ -558,6 +534,59 @@ def ohlcv(symbol: str,
558534
logger.error('Oops! An error Occurred ⚠️')
559535
raise InvalidCredentials(response.text)
560536

537+
def time_and_sale(symbol: str,
538+
start: str,
539+
end: str,
540+
interval: str,
541+
data_filter: str = "all",
542+
brokerage: typing.Any = USER_BROKERAGE,
543+
access_token: str = USER_ACCESS_TOKEN,
544+
dataframe: bool = True)->dict:
545+
'''get time and sale data'''
546+
if brokerage == "Tradier Inc.":
547+
url = TR_BROKERAGE_API_URL
548+
elif brokerage == "miscpaper":
549+
url = TR_SANDBOX_BROKERAGE_API_URL
550+
else:
551+
logger.error('Oops! An error Occurred ⚠️')
552+
raise InvalidBrokerage
553+
554+
if interval not in ("1m", "5m", "15m"):
555+
logger.error('Oops! An error Occurred ⚠️')
556+
raise InvlaidTimeInterval(
557+
'Invalid Time Interval. Available time intervals for this function are: "1m", "5m", "15m"'
558+
)
559+
interval_dict={'1m':'1min','5m':'5min','15m':'15min'}
560+
params = {
561+
"symbol": str.upper(symbol),
562+
"interval": interval_dict[interval],
563+
"start": start,
564+
"end": end,
565+
"session_filter": str(data_filter),
566+
}
567+
response = requests.get(
568+
"{}/v1/markets/timesales".format(url),
569+
headers=tr_get_headers(access_token),
570+
params=params,
571+
)
572+
if response:
573+
if not dataframe:
574+
return response.json()
575+
else:
576+
data = response.json()["series"]["data"]
577+
dataframe = pandas.DataFrame(data)
578+
dataframe['datetime'] = pandas.to_datetime(dataframe['time'])
579+
dataframe.set_index(['datetime'], inplace=True)
580+
del dataframe['time']
581+
del dataframe['timestamp']
582+
return dataframe
583+
if response.status_code == 400:
584+
logger.error('Oops! An error Occurred ⚠️')
585+
raise BadRequest(response.text)
586+
if response.status_code == 401:
587+
logger.error('Oops! An error Occurred ⚠️')
588+
raise InvalidCredentials(response.text)
589+
561590

562591
def stream_live_quotes(symbol: str,
563592
brokerage: str = USER_BROKERAGE,

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
packages=['libkloudtrader'],
99
url='https://github.com/KloudTrader/kloudtrader',
1010
license='LICENSE',
11-
description="kloudTrader's in-house library that makes it much easier for you to code algorithms that can trade for you.",
11+
description="KloudTrader's in-house library that makes it much easier for you to code algorithms that can trade for you.",
1212
long_description_content_type="text/markdown",
1313
long_description='pypi.md',
1414
install_requires=[

0 commit comments

Comments
 (0)