Using data from csv file in 60 minute format. Trying to log all buy/sell decisions using backtrader backtester.
Issue: The time logger doesn't seem to work properly as all hours are outputted as "23:59:59.999989" when this is not the case.
See sample code:
def log(self, txt, dt=None):
dt = dt or self.data.datetime.datetime(0)
print('%s, %s' % (dt, txt))
def next(self):
if self.data.close > self.sma1:
self.buy()
self.log('BUY CREATE, exectype Market, price %.2f' % self.data.close[0])
#Get Data
data = btfeeds.GenericCSVData(dataname='AAPL.csv',fromdate=datetime.datetime(2018, 1, 2),todate=datetime.datetime(2020, 4, 28),nullvalue=0.0,dtformat=('%Y-%m-%d %H:%M:%S'),datetime=0,open=1,low=2,high=3,close=4,volume=5,openinterest=6)
Sample Output:
2019-07-12 23:59:59.999989, BUY CREATE, exectype Market, price 203.52
2019-07-12 23:59:59.999989, BUY CREATE, exectype Market, price 203.30
2019-07-12 23:59:59.999989, BUY CREATE, exectype Market, price 203.24
2019-07-12 23:59:59.999989, BUY CREATE, exectype Market, price 203.24
2019-07-15 23:59:59.999989, BUY CREATE, exectype Market, price 204.11
Data & Format from Csv file:
2018-01-02 9:30:00 AM
This problem also took me few hours. And I find the solution from another web. enter link description here
For minute data tell cerebro that you are using minute data (timeframe) and how many minutes per bar (compression).
#Get Data
data = btfeeds.GenericCSVData(
dataname='AAPL.csv',
fromdate=datetime.datetime(2018, 1, 2),
todate=datetime.datetime(2020, 4, 28),
nullvalue=0.0,
dtformat=('%Y-%m-%d %H:%M:%S'),
**timeframe=bt.TimeFrame.Minutes,**
datetime=0,
open=1,
low=2,
high=3,
close=4,
volume=5,
openinterest=6)
Related
I I am trying to make a Crypto Barometer. I have a little piece of code that gets the price in USD for each symbol. Now I want to add them up and get the total of these coins (the prices of one of each coin). I got the realtime prices, but I don't know how to add them up. I also want the price of each symbol one, four, eight and 24 hours ago...
In the end it should look like this :
Current 1Hour ... 24Hours
BTCUSDT $49343.34 BTCUSDT $49133.12 BTCUSDT $48763.34
... ... ..
ETHUSDT $2123.84 ETHUSDT $2087.53 ETHUSDT $1987.23
sum : $6255422.23 Sum : $6249983m92 Sum : 6187291.51
Here is my code so far:
import requests
import json
import datetime
import time
api_request = requests.get('https://api.binance.com/api/v3/ticker/price')
api = json.loads(api_request.content)
for x in api:
print(x['symbol'], "${0:.4f}".format(float(x['price'])))
# THE PART WHERE I GOT DIFFERENT TIMES
while True:
dt = datetime
cur_time = (dt.datetime.now().strftime('%d-%m %H:%M'))
one_hour = (dt.datetime.now() - dt.timedelta(hours=1)).strftime('%d-%m %H:%M')
four_hours = (dt.datetime.now() - dt.timedelta(hours=4)).strftime('%d-%m %H:%M')
eight_hours = (dt.datetime.now() - dt.timedelta(hours=8)).strftime('%d-%m %H:%M')
one_day = (dt.datetime.now() - dt.timedelta(hours=24)).strftime('%d-%m %H:%M')
print(cur_time)
print(one_hour)
print(four_hours)
print(eight_hours)
print(one_day)
time.sleep(60)
there is a API library to get prices of nearly every crypto
import cryptocompare
def crypto_price('BTC'):
coin_acronym = str(acronyms['BTC'])
price_crypto = cryptocompare.get_price(coin_acronym, currency='USD', full=True).get('RAW').get(coin_acronym).get(
'USD').get(
'PRICE')
return price_crypto
This is a simple trading bot working with gate.io api. It does almost what we want but 2 features are missing.
1-When I enter the token name in the terminal, it has to automatically buy it 3% more than the market price.
2-When the price rises as much as I have determined, it has to automatically sell back all the tokens it bought.
How can I add these features?
import ccxt, time
import utils.config
from utils.telegram_bot import post_message
# Create the GateIO exchange object using CCXT
exchange = ccxt.gateio({
'apiKey': utils.config.GATEIO_API_KEY,
'secret': utils.config.GATEIO_SECRET_KEY,
})
# Get the market and balance data from GateIO
markets = exchange.fetch_markets()
balance = exchange.fetch_total_balance()
# Get all the available symbols from GateIO
symbols = [symbol for symbol in [market['symbol'] for market in markets]]
# Placeholder for keeping the price at the time of buying
entryPrice = 0
def symbol_check(symbol):
if symbol in symbols:
print(f"Good news!, {symbol} exists in Gate.io")
return True
else:
print(f"Sorry, {symbol} does not exist in Gate.io")
return False
def buy(symbol):
global entryPrice
# Pick a price more than the last ticker data, to make sure that we can fulfill order
price = exchange.fetch_ticker(symbol)['last'] * 1.01
entryPrice = price
# Get the current USDT balance in GateIO
balance = exchange.fetch_total_balance()
coin = symbol.split('/')[0]
usdt_balance = balance['USDT']
# Calculate the amount of coin that we can buy, apply a small margin for rounding errors in balance
amount = (usdt_balance * 0.999) / (price)
# Create the limit buy order
exchange.create_limit_buy_order(symbol, amount=amount, price=price)
# Notify the user both on Telegram and CLI
message = f"You have {usdt_balance} USDT in your account. Buying {amount} {coin} for {price}"
print(message)
post_message(message)
def sell(symbol):
# Pick a price less than the last ticker data, to make sure that we can fulfill order
price = exchange.fetch_ticker(symbol)['last'] * 0.99
# Get the current coin balance in GateIO
balance = exchange.fetch_total_balance()
coin = symbol.split('/')[0]
coin_balance = balance[coin]
# Create the limit sell order
exchange.create_limit_sell_order(symbol, amount=coin_balance, price=price)
# Notify the user both on Telegram and CLI
message = f"You have {coin_balance} {coin} in your account. Selling them for {price}"
print(message)
post_message(message)
def sellBearish(symbol):
global entryPrice
bestPrice = exchange.fetch_ticker(symbol)['last']
balance = exchange.fetch_total_balance()
while True:
price = exchange.fetch_ticker(symbol)['last']
# Update the best price if we have a new best price
if price > bestPrice:
bestPrice = price
# If the price has dropped 3% percent w.r.t. the best price, sell the coins and get the profit
elif price < (0.97 * bestPrice):
coin = symbol.split('/')[0]
coin_balance = balance[coin]
exchange.create_limit_sell_order(symbol, amount=coin_balance, price=price*0.99)
# Notify the user both on Telegram and CLI
message = f"You have {coin_balance} {coin} in your account.\nSelling them for {price*0.99}\nYour profit is{price/entryPrice*100}"
print(message)
post_message(message)
I'm downloading historical candlestick data for multiple crypto pairs across different timeframes from the binance api, i would like to know how to sort this data according to pair and timeframe and check which pair on which timeframe executes my code, the following code is what i use to get historical data
import requests
class BinanceFuturesClient:
def __init__(self):
self.base_url = "https://fapi.binance.com"
def make_requests(self, method, endpoint, data):
if method=="GET":
response = requests.get(self.base_url + endpoint, params=data)
return response.json()
def get_symbols(self):
symbols = []
exchange_info = self.make_requests("GET", "/fapi/v1/exchangeInfo", None)
if exchange_info is not None:
for symbol in exchange_info['symbols']:
if symbol['contractType'] == 'PERPETUAL' and symbol['quoteAsset'] == 'USDT':
symbols.append(symbol['pair'])
return symbols
def initial_historical_data(self, symbol, interval):
data = dict()
data['symbol'] = symbol
data['interval'] = interval
data['limit'] = 35
raw_candle = self.make_requests("GET", "/fapi/v1/klines", data)
candles = []
if raw_candle is not None:
for c in raw_candle:
candles.append(float(c[4]))
return candles[:-1]
running this code
print(binance.initial_historical_data("BTCUSDT", "5m"))
will return this as the output
[55673.63, 55568.0, 55567.89, 55646.19, 55555.0, 55514.53, 55572.46, 55663.91, 55792.83, 55649.43,
55749.98, 55680.0, 55540.25, 55470.44, 55422.01, 55350.0, 55486.56, 55452.45, 55507.03, 55390.23,
55401.39, 55478.63, 55466.48, 55584.2, 55690.03, 55760.81, 55515.57, 55698.35, 55709.78, 55760.42,
55719.71, 55887.0, 55950.0, 55980.47]
which is a list of closes
i want to loop through the code in such a manner that i can return all the close prices for the pairs and timeframes i need and sort it accordingly, i did give it a try but am just stuck at this point
period = ["1m", "3m", "5m", "15m"]
binance = BinanceFuturesClient()
symbols = binance.get_symbols()
for symbol in symbols:
for tf in period:
historical_candles = binance.initial_historical_data(symbol, tf)
# store values and run through strategy
You can use my code posted below. It requires python-binance package to be installed on your environment and API key/secret from your Binance account. Method tries to load data by weekly chunks (parameter step) and supports resending requests on failures after timeout. It may helps when you need to fetch huge amount of data.
import pandas as pd
import pytz, time, datetime
from binance.client import Client
from tqdm.notebook import tqdm
def binance_client(api_key, secret_key):
return Client(api_key=api_key, api_secret=secret_key)
def load_binance_data(client, symbol, start='1 Jan 2017 00:00:00', timeframe='1M', step='4W', timeout_sec=5):
tD = pd.Timedelta(timeframe)
now = (pd.Timestamp(datetime.datetime.now(pytz.UTC).replace(second=0)) - tD).strftime('%d %b %Y %H:%M:%S')
tlr = pd.DatetimeIndex([start]).append(pd.date_range(start, now, freq=step).append(pd.DatetimeIndex([now])))
print(f' >> Loading {symbol} {timeframe} for [{start} -> {now}]')
df = pd.DataFrame()
s = tlr[0]
for e in tqdm(tlr[1:]):
if s + tD < e:
_start, _stop = (s + tD).strftime('%d %b %Y %H:%M:%S'), e.strftime('%d %b %Y %H:%M:%S')
nerr = 0
while nerr < 3:
try:
chunk = client.get_historical_klines(symbol, timeframe.lower(), _start, _stop)
nerr = 100
except e as Exception:
nerr +=1
print(red(str(e)))
time.sleep(10)
if chunk:
data = pd.DataFrame(chunk, columns = ['timestamp', 'open', 'high', 'low', 'close', 'volume', 'close_time', 'quote_av', 'trades', 'tb_base_av', 'tb_quote_av', 'ignore' ])
data.index = pd.to_datetime(data['timestamp'].rename('time'), unit='ms')
data = data.drop(columns=['timestamp', 'close_time']).astype(float).astype({
'ignore': bool,
'trades': int,
})
df = df.append(data)
s = e
time.sleep(timeout_sec)
return df
How to use
c = binance_client(<your API code>, <your API secret>)
# loading daily data from 1/Mar/21 till now (your can use other timerames like 1m, 5m etc)
data = load_binance_data(c, 'BTCUSDT', '2021-03-01', '1D')
It returns indexed DataFrame with loaded data:
time
open
high
low
close
volume
quote_av
trades
tb_base_av
tb_quote_av
ignore
2021-03-02 00:00:00
49595.8
50200
47047.6
48440.7
64221.1
3.12047e+09
1855583
31377
1.52515e+09
False
2021-03-03 00:00:00
48436.6
52640
48100.7
50349.4
81035.9
4.10952e+09
2242131
40955.4
2.07759e+09
False
2021-03-04 00:00:00
50349.4
51773.9
47500
48374.1
82649.7
4.07984e+09
2291936
40270
1.98796e+09
False
2021-03-05 00:00:00
48374.1
49448.9
46300
48751.7
78192.5
3.72713e+09
2054216
38318.3
1.82703e+09
False
2021-03-06 00:00:00
48746.8
49200
47070
48882.2
44399.2
2.14391e+09
1476474
21500.6
1.03837e+09
False
Next steps are up to you and dependent on how would you like to design your data structure. In simplest case you could store data into dictionaries:
from collections import defaultdict
data = defaultdict(dict)
for symbol in ['BTCUSDT', 'ETHUSDT']:
for tf in ['1d', '1w']:
historical_candles = load_binance_data(c, symbol, '2021-05-01', timeframe=tf)
# store values and run through strategy
data[symbol][tf] = historical_candles
to get access to your OHLC you just need following: data['BTCUSDT']['1d'] etc.
Many buy orders are cancelled in the backtests and I cannot find why. Looking at the Writefile log it seems the buy orders are created at the next day's close. In most cases the buy price is in the day's range but still not executed.
I have tried on different assets, different sizes of the data feed, different strategies, with the same result.
Running on Jupyter notebook. I include the code and the log.
Finally I changed the default parameter ('100') in AllInSizerInt() below 100 and it worked. I do not really understand why, I thought the sizer would get the cash position from the broker and adjust the order.
Here is the fix:
''''
python
#Add the sizer. We plan to go 'all in' every time
cerebro.addsizer(bt.sizers.AllInSizerInt, percents = 95)
''''
And here is the original code:
''''
python
#### Import databases
from datetime import datetime
import backtrader as bt
import backtrader.indicators as btind
abspath = '/mypath/'
logfile = 'abs_momentum.csv'
# Create a Strategy
class Abs_momentum(bt.Strategy):
alias = ('Abs_momentum',)
params = (
# period for momentum calculation
('lookback', 252),
('range', 100))
def __init__(self):
# keep track of close price in the series
self.data_close = self.datas[0].close
# keep track of pending orders/buy price/buy commission
self.order = None
self.price = None
self.comm = None
# add a momentum indicator
self.mom = btind.MomentumOsc(self.data_close, \
period = self.p.lookback, \
band = self.p.range)
self.buysig = self.mom
def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
return
# Check if an order has been completed
# Attention: broker could reject order if not enough cash
if order.status in [order.Completed]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
#self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def next(self):
# do nothing if an order is pending
if self.order:
return
# check if there is already a position
if not self.position:
# buy condition
if self.buysig > 100:
self.log(f'BUY CREATED --- Price: {self.data_close[0]:.2f}')
self.order = self.buy(size = None)
else:
# sell condition
if self.buysig < 100:
self.log(f'SELL CREATED --- Price: {self.data_close[0]:.2f}')
self.order = self.sell(Size = None)
###
#### Download data from Yahoo Finance
data = bt.feeds.YahooFinanceData(dataname= 'SPY', \
fromdate=datetime(2018, 6, 15),\
todate=datetime(2021, 3, 17),\
reverse = False)
####
# create a Cerebro entity
cerebro = bt.Cerebro(stdstats = False)
### Set up the backtest
# Add the Data Feed to Cerebro
cerebro.adddata(data)
# Set our desired cash start
cerebro.broker.setcash(100000.0)
# Set the commission - 0.1% ... divide by 100 to remove the %
cerebro.broker.setcommission(commission=0.001)
#Add the sizer. We plan to go 'all in' every time
cerebro.addsizer(bt.sizers.AllInSizerInt)
#Add the strategy
cerebro.addstrategy(Abs_momentum)
#Add the observers to the plot
cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
#Write to a csv file
cerebro.addwriter(bt.WriterFile, out = (abspath + logfile), csv=True,\ data(csv) = False)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Run over everything
cerebro.run()
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
###
### Plot the results
cerebro.plot(iplot=True, volume=False)
###
''''
Here is the log:
>Starting Portfolio Value: 100000.00
>2019-06-18, BUY CREATED --- Price: 282.95
>2019-06-19, Order Canceled/Margin/Rejected
>2019-06-19, BUY CREATED --- Price: 283.58
>2019-06-20, Order Canceled/Margin/Rejected
>2019-06-20, BUY CREATED --- Price: 286.29
>2019-06-21, Order Canceled/Margin/Rejected
>2019-06-21, BUY CREATED --- Price: 285.88
>2019-06-24, BUY EXECUTED, Price: 286.10, Cost: 99848.90, Comm 99.85
>2020-03-12, SELL CREATED --- Price: 243.56
>2020-03-13, SELL EXECUTED, Price: 258.27, Cost: 99848.90, Comm 90.14
>2020-03-13, OPERATION PROFIT, GROSS -9712.67, NET -9902.66
>2020-04-17, BUY CREATED --- Price: 283.04
>2020-04-20, BUY EXECUTED, Price: 279.06, Cost: 88741.08, Comm 88.74
>2020-04-20, SELL CREATED --- Price: 278.05
>2020-04-21, SELL EXECUTED, Price: 273.25, Cost: 88741.08, Comm 86.89
>2020-04-21, OPERATION PROFIT, GROSS -1847.58, NET -2023.21
>2020-04-29, BUY CREATED --- Price: 289.53
>2020-04-30, Order Canceled/Margin/Rejected
>2020-04-30, BUY CREATED --- Price: 286.83
>2020-05-01, Order Canceled/Margin/Rejected
>2020-05-06, BUY CREATED --- Price: 280.68
>2020-05-07, Order Canceled/Margin/Rejected
>2020-05-07, BUY CREATED --- Price: 284.07
>2020-05-08, Order Canceled/Margin/Rejected
>2020-05-08, BUY CREATED --- Price: 288.77
>2020-05-11, BUY EXECUTED, Price: 286.69, Cost: 87153.76, Comm 87.15
>Final Portfolio Value: 121189.86
The reason your adjustment from 100% size trade to 95% size trade corrected the problem is that trying to by all in 100% on a portfolio will always result in some margins along the way . This can be seen here in your logs:
>2019-06-19, Order Canceled/Margin/Rejected
The problem is you are calculating the number of shares to trade off the previous close. If the market price gaps up on the next bar, you won't have enough cash to buy. There is an option called cheat-on-open that allows a peak at the next open price to permit sizing of the shares. This helps.
But in reality, it's best to trade below 100%.
I am learning and using the pandas and python.
Today, I am trying to make a fx rate table,
but I got a trouble with getting the pricess of 'USDJPY'.
When I get a prices of 'EUR/USD', i code like this.
eur = web.DataReader('EURUSD=X','yahoo')['Adj Close']
it works.
But when I wrote
jpy = web.DataReader('USDJPY=X','yahoo')['Adj Close']
the error message comes like this:
--------------------------------------------------------------------------- IOError Traceback (most recent call
last) in ()
----> 1 jpy = web.DataReader('USDJPY=X','yahoo')['Adj Close']
C:\Anaconda\lib\site-packages\pandas\io\data.pyc in DataReader(name,
data_source, start, end, retry_count, pause)
70 return get_data_yahoo(symbols=name, start=start, end=end,
71 adjust_price=False, chunksize=25,
---> 72 retry_count=retry_count, pause=pause)
73 elif data_source == "google":
74 return get_data_google(symbols=name, start=start, end=end,
C:\Anaconda\lib\site-packages\pandas\io\data.pyc in
get_data_yahoo(symbols, start, end, retry_count, pause, adjust_price,
ret_index, chunksize, name)
388 """
389 return _get_data_from(symbols, start, end, retry_count, pause,
--> 390 adjust_price, ret_index, chunksize, 'yahoo', name)
391
392
C:\Anaconda\lib\site-packages\pandas\io\data.pyc in
_get_data_from(symbols, start, end, retry_count, pause, adjust_price, ret_index, chunksize, source, name)
334 # If a single symbol, (e.g., 'GOOG')
335 if isinstance(symbols, (basestring, int)):
--> 336 hist_data = src_fn(symbols, start, end, retry_count, pause)
337 # Or multiple symbols, (e.g., ['GOOG', 'AAPL', 'MSFT'])
338 elif isinstance(symbols, DataFrame):
C:\Anaconda\lib\site-packages\pandas\io\data.pyc in
_get_hist_yahoo(sym, start, end, retry_count, pause)
188 '&g=d' +
189 '&ignore=.csv')
--> 190 return _retry_read_url(url, retry_count, pause, 'Yahoo!')
191
192
C:\Anaconda\lib\site-packages\pandas\io\data.pyc in
_retry_read_url(url, retry_count, pause, name)
167
168 raise IOError("after %d tries, %s did not "
--> 169 "return a 200 for url %r" % (retry_count, name, url))
170
171
IOError: after 3 tries, Yahoo! did not return a 200 for url
'http://ichart.yahoo.com/table.csv?s=USDJPY=X&a=0&b=1&c=2010&d=1&e=1&f=2014&g=d&ignore=.csv'
Other currencies like 'GBPUSD' also have same problem.
Can you solve this problem?
Do you have any idea of getting 'USDJPY' from yahoo or google???
Yahoo Finance doesn't provide historical data on exchange rates (i.e. there's no "Historical Prices" link in the top left of the page like there would be for stocks, indices, etc...)
You can use FRED (Federal Reserve of St. Louis data) to get these exchange rates...
import pandas.io.data as web
jpy = web.DataReader('DEXJPUS', 'fred')
UPDATE: hase moved the pandas-datareader
from pandas_datareader import data
jpy = data.DataReader('DEXJPUS', 'fred')
or the more direct way...
jpy = web.get_data_fred('DEXJPUS')
A list of all of the exchange rate that FRED has daily data for can be found here: http://research.stlouisfed.org/fred2/categories/94
Yahoo Finance doesn't provide historical data on exchange rates
Yes it does but not on cross rates. All vs the USD
List of Yahoo USD Exchange Rates
a = web.DataReader("JPY=X", 'yahoo')
The free and easy way is Yahoo:
# get fx rates
# https://finance.yahoo.com/currencies
# example EUR/USD = EURUSD%3DX?p=EURUSD%3DX
import pandas as pd
import pandas_datareader as dr
# change date range here
start_date = '2021-02-26'
end_date = '2021-03-01'
# retrieve market data of current ticker symbol
print('This is the table with HLOC, Volume, Adj Close prices')
eurusd = dr.data.DataReader('EURUSD%3DX', data_source='yahoo', start=start_date, end=end_date)
print(eurusd)
# just get latest adjusted close for further use
print('This is the Adj Close prices only')
print(eurusd['Adj Close'])
and it also works with other crosses, contrary to the above statements:
# EURCHF%3DX
eurchf = dr.data.DataReader('EURCHF%3DX', data_source='yahoo', start=start_date, end=end_date)
print(eurchf)
Get the historical exchange rates from OANDA
http://pandas-datareader.readthedocs.io/en/latest/remote_data.html
In [1]: from pandas_datareader.oanda import get_oanda_currency_historical_rates
In [2]: start, end = "2016-01-01", "2016-06-01"
In [3]: quote_currency = "USD"
In [4]: base_currency = ["EUR", "GBP", "JPY"]
In [5]: df_rates = get_oanda_currency_historical_rates(
start, end,
quote_currency=quote_currency,
base_currency=base_currency
)
In [6]: print(df_rates)
Update: Oanda started charging for this lately
https://www.oanda.com/fx-for-business/exchange-rates-api
#!pip install yfinance
#!pip install mplfinance
from datetime import datetime
import yfinance as yf
import mplfinance as mpf
#import pandas as pd
#import pandas_datareader as dr
# change date range here
start_date = '2021-02-26'
end_date = '2021-03-01'
#This Does NOT WORK#
# retrieve market data of current ticker symbol
print('This is the table with HLOC, Volume, Adj Close prices')
eurusd = dr.data.DataReader('EURUSD%3DX', data_source='yahoo',
start=start_date, end=end_date)
print(eurusd)
#This Does#
data = yf.download('USDCAD=X', start=start_date, end=end_date)
#If someone can figure out how to get the S5,S30, M1, M3 etc. Please share
I think you can use custom intervals by passing it as an argument to the yf.download() function. For example:
data = yf.download('USDCAD=X', start=start_date, end=end_date, interval='1m')