indicator 목록
https://www.quantconnect.com/docs/algorithm-reference/indicators#Indicators-Reference-Table
.
.
fine filter로 사용가능한 900정도의 지표 목록
https://www.quantconnect.com/docs/data-library/fundamentals#Fundamentals-Reference-Tables
https://www.quantconnect.com/docs/algorithm-reference/indicators#Indicators-Reference-Table
.
.
https://www.quantconnect.com/docs/data-library/fundamentals#Fundamentals-Reference-Tables
# schedule an event to fire at a specific date/time self.Schedule.On(self.DateRules.On(2013, 10, 7), self.TimeRules.At(13, 0), self.SpecificTime) # schedule an event to fire every trading day for a security the # time rule here tells it to fire 10 minutes after SPY's market open self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen(self.spy, 10), self.EveryDayAfterMarketOpen) # schedule an event to fire every trading day for a security the # time rule here tells it to fire 10 minutes before SPY's market close self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 10), self.EveryDayBeforeMarketClose) # schedule an event to fire on certain days of the week self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Friday), self.TimeRules.At(12, 0), self.EveryMonFriAtNoon) # the scheduling methods return the ScheduledEvent object which can be used # for other things here I set the event up to check the portfolio value every # 10 minutes, and liquidate if we have too many losses self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(minutes=10)), self.LiquidateUnrealizedLosses) # schedule an event to fire at the beginning of the month, the symbol is # optional. # if specified, it will fire the first trading day for that symbol of the month, # if not specified it will fire on the first day of the month self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY"), self.RebalancingCode)
.
hese are provided in two ways: through helper short cut methods, and as class objects. Indicators created through the short cut methods have already been wired up to receive data and are “ready to use”
.
One key indicator to learn is the Identity indicator, which simply returns the value of the asset.
pep = Identity("PEP") # Pepsi ticker coke = Identity("KO") # Coke ticker delta = IndicatorExtensions.Minus(pep, coke) # Difference between them
.
if not self.indicator.IsReady: return
.
def Initialize(self): self.AddEquity("SPY", Resolution.Hour) # define a 10-period daily RSI indicator with shortcut helper method self.rsi = self.RSI("SPY", 10, MovingAverageType.Simple, Resolution.Daily) # set a warm-up period to initialize the indicator self.SetWarmUp(timedelta(20)) # Warm-up the indicator with bar count # self.SetWarmUp(10, Resolution.Daily)
Universe Selection does not support warm-up and, consequently, factors that depend on indicators are not updated.
.
def Initialize(self): self.AddEquity("SPY", Resolution.Hour) # define a 10-period daily RSI indicator with shortcut helper method self.rsi = self.RSI("SPY", 10, MovingAverageType.Simple, Resolution.Daily) # initialize the indicator with the daily history close price history = self.History(["SPY"], 10, Resolution.Daily) for time, row in history.loc["SPY"].iterrows(): self.rsi.Update(time, row["close"])
.
The indicator resolution can be different from the resolution of your securities data. However, the resolution of the indicator should be equal to or higher than the resolution of your security.
def Initialize(self): # request the hourly equity data self.AddEquity("SPY", Resolution.Hour) # define a 10-period daily RSI indicator with shortcut helper method self.rsi = self.RSI("SPY", 10, MovingAverageType.Simple, Resolution.Daily) def OnData(self, data): # check if this algorithm is still warming up if self.rsi.IsReady: # get the current RSI value rsi_value = self.rsi.Current.Value # get the current average gain of rsi average_gain = self.rsi.AverageGain.Current.Value # get the current average loss of rsi average_loss = self.rsi.AverageLoss.Current.Value
.
# request the daily equity data self.AddEquity("SPY", Resolution.Daily) # define a 10-period RSI indicator with indicator constructor self.rsi = RelativeStrengthIndex(10, MovingAverageType.Simple) # register the daily data of "SPY" to automatically update the indicator self.RegisterIndicator("SPY", self.rsi, Resolution.Daily)
.
RegisterIndicator()를 통하면 indicator에 필요한 값들이 자동 업데이트 된다.
# request the equity data in minute resolution self.AddEquity("SPY", Resolution.Minute) # define a 10-period RSI indicator with indicator constructor self.rsi = RelativeStrengthIndex(10, MovingAverageType.Simple) # create the 30-minutes data consolidator thirtyMinuteConsolidator = TradeBarConsolidator(timedelta(minutes=30)) self.SubscriptionManager.AddConsolidator("SPY", thirtyMinuteConsolidator) # register the 30-minute consolidated bar data to automatically update the indicator self.RegisterIndicator("SPY", self.rsi, thirtyMinuteConsolidator)
.
def Initialize(self): self.AddEquity("SPY", Resolution.Daily) self.rsi = RelativeStrengthIndex(10, MovingAverageType.Simple) def OnData(self, data): # update the indicator value with the new input close price every day if data.Bars.ContainsKey("SPY"): self.rsi.Update(data["SPY"].EndTime, data["SPY"].Close) # check if the indicator is ready if self.rsi.IsReady: # get the current RSI value rsi_value = self.rsi.Current.Value
.
# define a 10-period daily RSI indicator with shortcut helper method # select the Open price to update the indicator self.rsi = self.RSI("SPY", 10, MovingAverageType.Simple, Resolution.Daily, Field.Open)
# define a 10-period RSI with indicator constructor self.rsi = RelativeStrengthIndex(10, MovingAverageType.Simple) # register the daily High price data to automatically update the indicator self.RegisterIndicator("SPY", self.rsi, Resolution.Daily, Field.High)
.
.
self.Plot(string chart, Indicator[] indicators)
#Plot array of indicator objects; extending "Indicator" type. self.Plot("Indicators", sma, rsi); #Plot array of indicator objects; extending "TradeBarIndicator" type. self.Plot("Indicators", atr, aroon); #Currently, there is a limit of 4 indicators for each Plot call #For complex plotting it might be easiest to simply plot your indicators individually.
.
RollingWindow
is an array of data that allows for reverse list access semantics, where the object with index [0] refers to the most recent item in the window, and index [Length-1] refers to the last item in the window,
self.closeWindow = RollingWindow[float](4) self.tradeBarWindow = RollingWindow[TradeBar](2) self.quoteBarWindow = RollingWindow[QuoteBar](2)
self.closeWindow.Add(data["SPY"].Close) self.tradeBarWindow.Add(data["SPY"]) self.quoteBarWindow.Add(data["EURUSD"])
currentClose = self.closeWindow[0] previousClose = self.closeWindow[1] oldestClose = self.closeWindow[self.closeWindow.Count-1]
# In Initialize, create the rolling windows def Initialize(self): # Create a Rolling Window to keep the 4 decimal self.closeWindow = RollingWindow[float](4) # Create a Rolling Window to keep the 2 TradeBar self.tradeBarWindow = RollingWindow[TradeBar](2) # Create a Rolling Window to keep the 2 QuoteBar self.quoteBarWindow = RollingWindow[QuoteBar](2) # In OnData, update the rolling windows def OnData(self, data): if data.ContainsKey("SPY"): # Add SPY bar close in the rolling window self.closeWindow.Add(data["SPY"].Close) # Add SPY TradeBar in rolling window self.tradeBarWindow.Add(data["SPY"]) if data.ContainsKey("EURUSD"): # Add EURUSD QuoteBar in rolling window self.quoteBarWindow.Add(data["EURUSD"])
.
# In Initialize, create the rolling windows def Initialize(self): # Creates an indicator and adds to a rolling window when it is updated self.SMA("SPY", 5).Updated += self.SmaUpdated self.smaWindow = RollingWindow[IndicatorDataPoint](5) # Adds updated values to rolling window def SmaUpdated(self, sender, updated): self.smaWindow.Add(updated)
Indicators emit an Updated
event after they have been updated. To create a rolling window of indicator points, we attach an event handler function to Updated
, which adds the last value of the indicator to the rolling window. The value is an IndicatorDataPoint object that represents a piece of data at a specific time.
.
Universe selection is the process of screening or filtering the assets you’d like to trade by some predetermined formula.
QuantConnect provides two universes; Coarse Universe, and Fine Universe for the US Equities Market. The QuantConnect Universe data is refreshed every day. You can also create custom universes of data which we’ll explore later in this section.
After passing through your filters, the algorithm needs you to return an array of Symbol
objects. LEAN automatically subscribes to these new symbols and adds them to your algorithm.
When you deselect an asset you currently own or have open orders, it will continue receiving data. This is to ensure the portfolio models are accurate. You can use the algorithm self.ActiveSecurities
property to get the list of assets currently in a universe. Additionally, even once removed from the universe the security object in the Securties collection is maintained for record keeping purposes (e.g. total fees accrued, volume traded).
By default, assets selected by universe selection are requested with minute resolution data. You can change the default selection by adjusting the UniverseSettings
property, which we’ll dive into below.
.
To use a coarse universe, you must request it using an AddUniverse() call from the Initialize() method of your algorithm. You should pass in a function that will be used to filter the stocks down to the assets you are interested in using.
class MyCoarseUniverseAlgorithm(QCAlgorithm): def Initialize(self): self.AddUniverse(self.MyCoarseFilterFunction) def MyCoarseFilterFunction(self, coarse): pass
def MyCoarseFilterFunction(self, coarse): sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True) filtered = [ x.Symbol for x in sortedByDollarVolume if x.Price > 10 and x.DollarVolume > 10000000 ] return filtered[:500]
# setup state storage in initialize method self.stateData = { } def MyCoarseFilterFunction(self, coarse): # We are going to use a dictionary to refer the object that will keep the moving averages for c in coarse: if c.Symbol not in self.stateData: self.stateData[c.Symbol] = SelectionData(c.Symbol, 200) # Updates the SymbolData object with current EOD price avg = self.stateData[c.Symbol] avg.update(c.EndTime, c.AdjustedPrice, c.DollarVolume) # Filter the values of the dict to those above EMA and more than $1B vol. values = [x for x in self.stateData.values() if x.is_above_ema and x.volume > 1000000000] # sort by the largest in volume. values.sort(key=lambda x: x.volume, reverse=True) # we need to return only the symbol objects return [ x.symbol for x in values[:10] ]
class SelectionData(object): def __init__(self, symbol, period): self.symbol = symbol self.ema = ExponentialMovingAverage(period) self.is_above_ema = False self.volume = 0 def update(self, time, price, volume): self.volume = volume if self.ema.Update(time, price): self.is_above_ema = price > ema
.
class SelectionData(object): def __init__(self, symbol, period): self.symbol = symbol self.volume = 0 self.volume_ratio = 0 self.sma = SimpleMovingAverage(period) def update(self, time, price, volume): self.volume = volume if self.sma.Update(time, volume): # get ratio of this volume bar vs previous 10 before it. self.volume_ratio = volume / self.sma.Current.Value
def CoarseFilterFunction(self, coarse): for c in coarse: if c.Symbol not in self.stateData: self.stateData[c.Symbol] = SelectionData(c.Symbol, 10) avg = self.stateData[c.Symbol] avg.update(c.EndTime, c.AdjustedPrice, c.DollarVolume) # filter the values of selectionData(sd) above SMA values = [sd for sd in self.stateData.values() if sd.volume > sd.sma.Current.Value and sd.volume_ratio > 0] # sort sd by the largest % jump in volume. values.sort(key=lambda sd: sd.volume_ratio, reverse=True) # return the top 10 symbol objects return [ sd.symbol for sd in values[:10] ]
.
Tip:
Only 5,000 assets have fundamental data. When working with fundamental data, you should always include the “HasFundamentalData” filter in your Coarse Universe filter.
.
To request a fundamental universe, pass a second filter-function into the
AddUniverse()
method.
class MyUniverseAlgorithm(QCAlgorithm): def Initialize(self): self.AddUniverse(self.MyCoarseFilterFunction, self.MyFineFundamentalFunction) def MyCoarseFilterFunction(self, coarse): pass def MyFineFundamentalFunction(self, fine): pass
.
# In Initialize: self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) def CoarseSelectionFunction(self, coarse): sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True) filtered = [ x.Symbol for x in sortedByDollarVolume if x.HasFundamentalData ] return filtered[:50] def FineSelectionFunction(self, fine): sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.PERatio, reverse=False) return [ x.Symbol for x in sortedByPeRatio[:10] ]
.
https://www.quantconnect.com/docs/data-library/fundamentals#Fundamentals-Morningstar-US-Equity-Data
.
Below is the UniverseSettings object and its default settings:
//Popular universe settings: self.UniverseSettings.Resolution // What resolution should added assets use .Leverage // What leverage should assets use in the universe? .FillForward // Should asset data fill forward? .MinimumTimeInUniverse // Minimum time assets should be in universe .ExtendedMarketHours // Should assets also feed extended market hours?
.
These settings should be configured in your Initialize()
method before you request your universe. They are globals, so they will apply to all universes you create.
class MyCustomSettingsUniverseAlgorithm(QCAlgorithm): def Initialize(self): # Request second resolution data. This will be slow! self.UniverseSettings.Resolution = Resolution.Second self.AddUniverse(self.MySecondResolutionCoarseFilterFunction)
.
When adding securities from the universe, some algorithms need raw or partially adjusted price data. This can be controlled by the SetSecurityInitializer()
method.
#In Initialize self.SetSecurityInitializer(self.CustomSecurityInitializer) def CustomSecurityInitializer(self, security): '''Initialize the security with raw prices''' security.SetDataNormalizationMode(DataNormalizationMode.Raw)
축약형
# Most common request; requesting raw prices for universe securities. self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))
.
When universe contents are changed (securities are added or removed from the algorithm), we generate an OnSecuritiesChanged event. This allows your algorithm to know the changes in the universe state. The event passes in the SecurityChanges object containing references to the Added and Removed securities.
def OnSecuritiesChanged(self, changes): self._changes = changes self.Log(f"OnSecuritiesChanged({self.UtcTime}):: {changes}")
a list of current securities is provided by the ActiveSecurities
property. This is a dictionary of Security objects which are currently in your universe.
.
/ Helper: Add US-equity universe for the top 50 stocks by dollar volume self.AddUniverse(self.Universe.DollarVolume.Top(50)) // Helper: Add US-equity universe for the bottom 50 stocks by dollar volume self.AddUniverse(self.Universe.DollarVolume.Bottom(50)) // Helper: Add US-equity universe for the 90th dollar volume percentile self.AddUniverse(self.Universe.DollarVolume.Percentile(90)) // Helper: Add US-equity universe for stocks between the 70th and 80th dollar volume percentile self.AddUniverse(self.Universe.DollarVolume.Percentile(70, 80))
.
# add the custom universe in initialize self.AddUniverse(NyseTopGainers, "myCustomUniverse", Resolution.Daily, self.nyseTopGainers) # filter function using your custom data def nyseTopGainers(self, data): return [ x.Symbol for x in data if x["Rank"] > 5 ]
# Example custom universe data; it is virtually identical to other custom data types. class NyseTopGainers(PythonData): def GetSource(self, config, date, isLiveMode): return SubscriptionDataSource(@"your-remote-universe-data", SubscriptionTransportMedium.RemoteFile) def Reader(self, config, line, date, isLiveMode): # Generate required data, then return an instance of your class. nyse = NyseTopGainers() nyse.Time = date # define end time as exactly 1 day after Time nyse.EndTime = nyse.Time + timedelta(1) nyse.Symbol = Symbol.Create(symbolString, SecurityType.Equity, Market.USA) nyse["Rank"] = rank return nyse
.
History
All python history requests return a Data Frame, which has different columns depending on the type of data requested. Data is returned as TradeBars, QuoteBars, or Slice objects depending on how you request it and the data available for your security.
Return Format
Slice
objects.Time Index
History data is returned in an ascending order from oldest to newest. This is required for piping the data into indicators to perform warm-up.
.
# EXAMPLE 1: Requesting By Bar Count: 5 IBM TradeBars, defaulting to security resolution:
self.AddEquity(“IBM”, Resolution.Daily)
self.df = self.History(self.Symbol(“IBM”), 5)
.
self.df = self.History([self.Symbol("IBM"), self.Symbol("AAPL")], 2)
.
Resolution.Minute
is selected..
The parameters are very similar to other history methods, but the return type is an array of Slice
objects. This has the same properties as the OnData() Slice object.
The Slice object holds all of the results in a sorted enumerable collection you can iterate over with a foreach loop.
# EXAMPLE 1: Requesting 5 Bars For All Securities, default to security resolution: # Setting Up Universe self.AddEquity("IBM", Resolution.Daily) self.AddEquity("AAPL", Resolution.Daily) # Request history data and enumerate results: slices = self.History(5) for s in slices: print(str(s.Time) + " AAPL:" + str(s.Bars["AAPL"].Close) + " IBM:" + str(s.Bars["IBM"].Close))
.
# EXAMPLE 2: Requesting 5 Minutes For All Securities: slices = self.History(timedelta(minutes=5), Resolution.Minute) for s in slices: print(str(s.Time) + " AAPL:" + str(s.Bars["AAPL"].Close) + " IBM:" + str(s.Bars["IBM"].Close))
.
Working with Data Frames
# Setup Universe: eurusd = self.AddForex("EURUSD", Resolution.Daily).Symbol nzdusd = self.AddForex("NZDUSD", Resolution.Daily).Symbol # STEP 1: Request Dataframe: self.df = self.History([eurusd, nzdusd], 3)
# STEP 2: Check if empty and lock onto a symbol index with the loc[] method: if not self.df.empty: eurusd_quotebars = self.df.loc["EURUSD"]
# STEP 3: Extract and manipulate a single column with the string column name: spread = eurusd_quotebars["askclose"] - eurusd_quotebars["bidclose"]
# STEP 3: Extract and manipulate a single column with the string column name: spread = eurusd_quotebars["askclose"] - eurusd_quotebars["bidclose"]
.
# UNSTACKING: Transform into columns: # Fetch multi-indexed history: self.dataframe = self.History([self.Symbol("IBM"), self.Symbol("AAPL")], 3)
# Transform using unstack: self.dataframe["close"].unstack(level=0)
.
# Wind time back 7 days from start: self.SetWarmup(timedelta(7)) # Feed in 100 bars before start date: self.SetWarmup(100)
# In Initialize self.emaFast = self.EMA("IBM", 50); self.emaSlow = self.EMA("IBM", 100); self.SetWarmup(100); // In OnData: Don't run if we're warming up our indicators. if self.IsWarmingUp: return
.
self.Plot("Series Name", value)
# In Initialize(self) self.macd = MACD("SPY", 12, 26,9, MovingAverageType.Exponential, Resolution.Daily) # In OnData(self, data) self.Plot("My Indicators", "MACD Signal", self.macd.Signal)
.
In your initialize method, you can use the AddChart(Chart obj) method to insert a new chart. Each chart object has an internal collection of Series objects.
In creating Series objects, you must specify the name of the series, the SeriesType , and the index the series operates on. The series index refers to its position in the chart – for example, if all the series are index 0, they will lay on top of each other. If each series has its own index, it will have several mini-charts stacked next to each other.
# In your initialize method: # Note - use single quotation marks: ' instead of double " # Chart - Master Container for the Chart: stockPlot = Chart('Trade Plot') # On the Trade Plotter Chart we want 3 series: trades and price: stockPlot.AddSeries(Series('Buy', SeriesType.Scatter, 0)) stockPlot.AddSeries(Series('Sell', SeriesType.Scatter, 0)) stockPlot.AddSeries(Series('Price', SeriesType.Line, 0)) # Or using custom chart # Import the necessary module before using Custom color from System.Drawing import Color stockPlot.AddSeries(Series('Price', SeriesType.Line, '$', Color.Green)) stockPlot.AddSeries(Series('Buy', SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle)) stockPlot.AddSeries(Series('Sell', SeriesType.Scatter, '$', Color.Blue, ScatterMarkerSymbol.TriangleDown)) self.AddChart(stockPlot) # Later in your OnData(self, data): self.Plot('Trade Plot', 'Price', data.Bars["SPY"].Close)
.
SeriesType.Line .Scatter .Candle .Bar .Flag
.
You can customize the chart color and the scatter symbol when creating the series. In your customized chart, instead of specifying the index, you need to specify the label name of the y-axis using a string like '$'
, '%'
, or an empty string ''
. The chart color can be changed by specifying the parameter "Color.ColorName"
.
ScatterMarkerSymbol.Circle .Diamond .Square .Triangle .TriangleDown
.
data storing
.
Algorithms can send debug messages to the console using the Debug(string message) method.
Algorithms can save more detailed messaging to log files for later analysis using Log(string message).
self.Debug(str(self.Time) + " Purchasing AAPL: " + str(slice["SPY"].Price))
self.Error("Volatility too high, terminating algorithm.") self.Quit() # Optional: Instruct algorithm to stop.
self.Log("Additional detailed logging messages")
QuantConnect annualizes the daily DTW. An annualized distance provides a user with a measurement of the annual difference in the magnitude of returns between the two curves. A perfect score is 0, meaning the returns for each day were precisely the same. A DTW score of 0 is nearly impossible to achieve, and we consider anything below 0.2 to be a decent score. A distance of 0.2 means the returns between an algorithm’s live and OOS performance deviated by 20% over a year.
What is Returns Correlation?
Returns correlation is the simple Pearson correlation between the live and OOS returns. Correlation gives us a rudimentary understanding of how the returns move together. Do they trend up and down at the same time? Do they deviate in direction or timing?
An algorithm’s returns correlation should be as close to 1 as possible. We consider a good score to be 0.8 or above, meaning that there is a strong positive correlation. This indicates that the returns move together most of the time and that for any given return you see from one of the curves, the other curve usually has a similar direction return (positive or negative).
.
.
QCAlgorithm, which provides some key helper properties for you to use: Security Manager, Portfolio Manager, Transactions Manager, Notification Manager, and Scheduling Manager. Along with hundreds of helper methods to make the API easy to use.
Securities property is a dictionary of Security objects. Each asset (equity, forex pair, etc) in your algorithm has a security object. All the models for a security live on these objects:
Portfolio is a dictionary of SecurityHolding classes. These classes track the individual portfolio items profit and losses, fees, and quantity held. e.g. self.Portfolio["IBM"].LastTradeProfit
.
Other helpers like Transactions , Schedule , Notify , and Universe have their own helper methods,
def QCAlgorithm { self.Securities; # Array of Security objects. self.Portfolio; # Array of SecurityHolding objects self.Transactions; # Transactions helper self.Schedule; # Scheduling helper self.Notify; # Email, SMS helper self.Universe; # Universe helper # Set up Requested Data, Cash, Time Period. def Initialize: # Other Event Handlers: def OnData(self, slice): def OnEndOfDay(self, symbol): def OnEndOfAlgorithm(): # Indicator Helpers def SMA(): }
.
.
In backtests you can set your starting capital using the self.SetCash(float cash)
method. In live trading this is ignored and your brokerage cash is used instead.
.
Backtesting uses the self.SetStartDate(int year, int month, int day)
and self.SetEndDate(int year, int month, int day)
methods
self.SetStartDate(2013,1,1) self.SetEndDate(2015,1,1) self.SetEndDate(datetime.now() - timedelta(1)) # Or use a relative date.
.
self.AddEquity("SPY") # Default to minute bars self.AddForex("EURUSD", Resolution.Second) # Set second bars.
# Setting the data normalization mode for the MSFT security to raw (pay dividends as cash) self.Securities["SPY"].SetDataNormalizationMode(DataNormalizationMode.Raw);
.
.
Often algorithms need some historical data to prime technical indicators, or populate historical data arrays. Using the SetWarmUp(TimeSpan period) or SetWarmUp(int barCount) methods you can specify a warm-up period.
During the warm-up period you cannot place a trade.
Algorithms can use the bool IsWarmingUp property to determine if the warm-up period has completed.
self.SetWarmUp(200) # Warm up 200 bars for all subscribed data. self.SetWarmUp(timedelta(7)) # Warm up 7 days of data.
.
In QuantConnect, we model your algorithm with margin-modeling by default, but you can select a cash account type. Cash accounts do not allow leveraged trading, whereas Margin accounts support 2-4x leverage on your account value.
Margin accounts with more than $25,000 in equity are eligible for pattern day trading margin limits. This increases your available leverage to 4x while the market is open and 2x overnight. To model this behavior in your algorithm, you must set your security MarginModel to PatternDayTradingMarginModel
.
SetBrokerageModel(BrokerageName brokerage, AccountType account)
#Brokerage model and account type: self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash) //Add securities and if required set custom margin models spy = self.AddEquity("SPY") # Default to minute bars spy.MarginModel = PatternDayTradingMarginModel()
.
self.SetBenchmark("SPY")
.
The primary event handler, Slice, groups all data types together at a single moment in time in the def OnData(self, slice):
handler.
All data uses DataDictionary
objects to group data by symbol and provide easy access to information. The plural of the type denotes the collection of objects (e.g., the TradeBars DataDictionary is made up of TradeBar objects; QuoteBars DataDictionary is made up of QuoteBar objects).
ibmTradeBar = slice.Bars["IBM"]
.
onData()를 통해서 slice obj가 전달된다. slice obj를 통해 각 ticker의 정보에 접근하는 방법은 아래와 같다.
class Slice: TradeBars Bars; QuoteBars QuoteBars; Ticks Ticks; OptionChains OptionChains; FuturesChains FuturesChains; Splits Splits; Dividends Dividends; Delistings Delistings; SymbolChangedEvents SymbolChangedEvents;
it is possible to check if the time slice contains specific data. e.g. slice.ContainsKey("EURUSD")
will return a boolean.
Even if requesting data to be filled forward, you should check if the data exists in the dictionary first.
.
There are seven financial data types: Tick, TradeBar, QuoteBar, Delisting, SymbolChangedEvent, Split, and Dividend. All data extends from BaseData, the core data class, which provides Symbol, Time, and Value properties.
.
self.AddEquity("IBM", Resolution.Hour) ## Subscribe to hourly TradeBars def OnData(self, data): ## You can access the TradeBar dictionary in the slice object and then subset by symbol ## to get the TradeBar for IBM tradeBars = data.Bars ibmTradeBar = tradeBars['IBM'] ibmOpen = ibmTradeBar.Open ## Open price ibmClose = ibmTradeBar.Close ## Close price ## Or you can access the IBM TradeBar by directly subsetting the slice object ## (since you are subscribed to IBM equity data, this will return a TradeBar rather than a QuoteBar) ibmOpen = data['IBM'].Open ## Open price imbClose = data['IBM'].Close ## Close price
.
Dividend events are triggered on payment of a dividend. It provides the Distribution per share.
def Initialize(self): self.SetStartDate(2017, 6, 1) self.SetEndDate(2017, 6, 28) self.spy = self.AddEquity("SPY", Resolution.Hour) def OnData(self, data): if not self.Portfolio.Invested: self.Buy("SPY", 100) ## Condition to see if SPY is in the Dividend DataDictionary if data.Dividends.ContainsKey("SPY"): ## Log the dividend distribution self.Log(f"SPY paid a dividend of {data.Dividends['SPY'].Distribution}")
.
def Initialize(self): self.SetStartDate(2003, 2, 1) self.SetEndDate(2003, 2, 28) self.SetCash(100000) self.msft = self.AddEquity("MSFT", Resolution.Daily) self.msft.SetDataNormalizationMode(DataNormalizationMode.Raw) def OnData(self, data): if not self.Portfolio.Invested: self.Buy("MSFT", 100) ## If MSFT had a split, print out information about it if data.Splits.ContainsKey("MSFT"): ## Log split information spySplit = data.Splits['MSFT'] if spySplit.Type == 0: self.Log('MSFT stock will split next trading day') if spySplit.Type == 1: self.Log("Split type: {0}, Split factor: {1}, Reference price: {2}".format(spySplit.Type, spySplit.SplitFactor, spySplit.ReferencePrice))
.
SymbolChangedEvents provides notice of new ticker names for stocks, or mergers of two tickers into one. It provides the OldSymbol and NewSymbol tickers.
.
Delisting events provide notice that an asset is no longer trading on the exchange. A delisting warning is issued on the final trading day for a stock delisting event to give your algorithm time to gracefully exit out of positions before forced termination.
.
LEAN supports backtesting almost any external custom data source. To use this feature, you need to add the data during initialize using self.AddData()
and instruct your algorithm on how to read your data. We provide helpers for popular data sources like Quandl and Intrinio, but if you are using your own format or server, you’ll need to create a custom type.
.
# In Initialize method: self.AddData(Weather, "KNYC", Resolution.Minute)
.
All data must extend from BaseData and override the Reader and GetSource methods.
.
class Weather(PythonData): ''' Weather based rebalancing''' def GetSource(self, config, date, isLive): source = "https://www.dropbox.com/s/8v6z949n25hyk9o/custom_weather_data.csv?dl=1" return SubscriptionDataSource(source, SubscriptionTransportMedium.RemoteFile); def Reader(self, config, line, date, isLive): # If first character is not digit, pass if not (line.strip() and line[0].isdigit()): return None data = line.split(',') weather = Weather() weather.Symbol = config.Symbol weather.Time = datetime.strptime(data[0], '%Y%m%d') + timedelta(hours=20) # Make sure we only get this data AFTER trading day - don't want forward bias. weather.Value = decimal.Decimal(data[2]) weather["MaxC"] = float(data[1]) weather["MinC"] = float(data[3]) return weather class MyAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 9, 20) # Set Start Date self.SetCash(100000) # Set Strategy Cash self.symbol = self.AddData(Weather, "KNYC", Resolution.Daily).Symbol def OnData(self, data): if data.ContainsKey(self.symbol): maxC = data[self.symbol].GetProperty('MaxC') minC = data[self.symbol].GetProperty('MaxC') value = data[self.symbol].Value
.
You may want to import a single static reference fileThis is possible with the Download() It can take header settings for authentication, and a username and password for basic authentication.
# If using dropbox remember to add the &dl=1 to trigger a download csv = self.Download("https://www.dropbox.com?....&dl=1") # read file (which needs to be a csv) to a pandas DataFrame. include following imports above # from io import StringIO # import pandas as pd df = pd.read_csv(StringIO(csv))
.
Intrinio Custom Data
# In Initialize method: self.AddData(IntrinioEconomicData, "$DCOILWTICO", Resolution.Daily)
https://docs.intrinio.com/documentation/web_api/get_all_economic_indices_v2
.
self.AddData(TiingoDailyData, "AAPL", Resolution.Daily)
.
Quandl.SetAuthCode("my-quandl-api-token")
.
Consolidating data allows you to create bars of any length from smaller bars. Commonly this is used to combine one-minute price bars into longer bars such as 10-20 minute bars.
To achieve this, QuantConnect allows you to create Consolidator
objects and register them for data.
self.Consolidate()
The consolidate helper accepts a timedelta
, Resolution
, or Calendar
period specifier:
# Consolidate 1min SPY -> 45min Bars self.Consolidate("SPY", timedelta(minutes=45), self.FortyFiveMinuteBarHandler) # Consolidate 1min SPY -> 1-Hour Bars self.Consolidate("SPY", Resolution.Hour, self.HourBarHandler) # Consolidate 1min SPY -> 1-Week Bars self.Consolidate("SPY", Calendar.Weekly, self.WeekBarHandler)
The event handler function of Consolidate
accepts one argument, the resulting bar. For most data sources, this defaults to TradeBar format.
# Example event handler from Consolidate helper. def FortyFiveMinuteBarHandler(self, consolidated): self.Log(f"{consolidated.EndTime} >> FortyFiveMinuteBarHandler >> {consolidated.Close}")
.
# Consolidating minute SPY into 14-bar daily indicators ema = self.EMA("SPY", 14, Resolution.Daily) sma = self.SMA("SPY", 14, Resolution.Daily)
# Generate 7 minute bars; then SMA-10 generates the average of last 10 bars. self.AddEquity("SPY", Resolution.Minute) self.sma = SimpleMovingAverage(10) self.RegisterIndicator("SPY", self.sma, timedelta(minutes=7))
.
# In initialize create a consolidator and add its bars to the window self.window = RollingWindow[TradeBar](2) self.Consolidate("SPY", timedelta(minutes=45), lambda x: self.window.Add(x)) # Now you can use the bar history; window[0] is current, window[1] is previous bar. if self.window.IsReady and window[0].Close > window[1].Close: self.Log("Current close price higher than the one 45 minutes ago")
.
def Initialize(self): self.AddEquity("QQQ", Resolution.Hour) threeCountConsolidator = TradeBarConsolidator(3) threeCountConsolidator.DataConsolidated += self.ThreeBarHandler self.SubscriptionManager.AddConsolidator("QQQ", threeCountConsolidator) def ThreeBarHandler(self, sender, bar): # With hourly data the bar period is 3-hours self.Debug(str(bar.EndTime - bar.Time) + " " + bar.ToString())
def Initialize(self): # Make sure you have the data you need self.AddEquity("QQQ", Resolution.Minute) # Create consolidator you need and attach event handler thirtyMinuteConsolidator = TradeBarConsolidator(timedelta(minutes=30)) thirtyMinuteConsolidator.DataConsolidated += self.ThirtyMinuteHandler # Register consolidator to get automatically updated with minute data self.SubscriptionManager.AddConsolidator("QQQ", thirtyMinuteConsolidator) def ThirtyMinuteHandler(self, sender, bar): # Bar period is now 30 min from the consolidator above. self.Debug(str(bar.EndTime - bar.Time) + " " + bar.ToString())
.
# self.Consolidate() Event Handler def FortyFiveMinuteBarHandler(self, consolidated): pass # Manually Created Event Handler def ThirtyMinuteBarHandler(self, sender, consolidated): pass
.
효율성을 위해 제거하는게 좋다.
# Remove a consolidator instance from subscription manager algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.myConsolidator)
.
Algorithms have a Securities property that stores a Security object for each asset in your algorithm. Security objects hold the models (backtesting behaviors) and properties of an asset. Each security can be completely customized to behave as you’d like. Securities is a Dictionary<Symbol, Security>
so you can access your Security objects with their ticker Securities["IBM"].Price
.
// Popular Securities Property Values: self.Securities["IBM"].HasData # Security has data .Invested # Have holdings .LocalTime # Time on the asset exchange .Holdings # Portfolio object .Exchange # Exchange information .FeeModel; # Fee model setter
The Portfolio property is a collection of SecurityHolding objects to provide easy access to the holding properties. Portfolio also provides information about the whole portfolio state:
// Popular Portfolio Property Values: self.Portfolio.Invested # Hold at least one stock .Cash # Sum of all currencies in account (only settled cash) .UnsettledCash # Sum of all currencies in account (only unsettled cash) .TotalFees # Fees incurred since backtest start .TotalHoldingsValue # Absolute sum portfolio items .MarginRemaining # Remaining margin on the account .TotalMarginUsed # Sum of margin used across all securities .TotalPortfolioValue # Portfolio equity .TotalProfit # Sum of all gross profit .TotalUnrealizedProfit # Holdings profit/loss
The Portfolio class is a Dictionary<Symbol, SecurityHolding>
, so it can be accessed via ticker index: Portfolio["IBM"].IsLong
// Popular Portfolio Property Values: self.Portfolio["IBM"].Invested .IsLong # IsLong, IsShort Holdings. .Quantity # Shares held. .UnrealizedProfit; # Holdings profit/loss .TotalFees # Fees incurred since backtest start .Price; # Asset price
Check out the Security (Securities objects), SecurityPortfolioManager class, and SecurityHolding (Portfolio objects) classes.
#Access to Security Objects with Securities: self.Securities["IBM"].Price
#Security object properties: class Security { Resolution Resolution; bool HasData; bool Invested; DateTime LocalTime; SecurityHolding Holdings; SecurityExchange Exchange; IFeeModel FeeModel; IFillModel FillModel; ISlippageModel SlippageModel; ISecurityPortfolioModel PortfolioModel; ISecurityMarginModel MarginModel; ISettlementModel SettlementModel; IVolatilityModel VolatilityModel; ISecurityDataFilter DataFilter; }
.
The ActiveSecurities lets you select the assets currently in your universe. This is useful for iterating over those securities from your universe selection. It has all the same properties as the Securities collection.
# Securities currently in the universe: self.ActiveSecurities["IBM"].HasData # Security has data .Invested # Have holdings .LocalTime # Time on the asset exchange .Holdings # Portfolio object .Exchange # Exchange information .FeeModel; # Fee model setter
.
Manual orders can be fetched, updated, and canceled with Order Tickets. As orders are filled and updated, they generate events that notify your algorithm about their execution.
You can control how optimistic or pessimistic these fills are with transaction model classes. In live trading, this fill price is set by your brokerage when the order is filled.
.
All of the methods return an OrderTicket, which you can use to update and cancel the orders. All orders should use the symbol object to place orders;
.
To update an order, you must use its OrderTicket.
Orders are updated by passing a UpdateOrderFields object to the Update method. The Update method returns an OrderResponse to signal the success or failure of the update request.
# Tag an order on creation ticket = self.LimitOrder("SPY", 100, 221.05, False, "New SPY trade") # Tag order later updateSettings = UpdateOrderFields() updateSettings.LimitPrice = 222.00 updateSettings.Tag = "Limit Price Updated for SPY Trade" response = ticket.Update(updateSettings) # Validate the response is OK if response.IsSuccessful: self.Debug("Order updated successfully")
.
To cancel an order, you must use its OrderTicket
The Cancel()
method returns an OrderResponse object to determine if the operation was successful.
# Create an order and save its ticket ticket = self.LimitOrder("SPY", 100, 221.05, False, "SPY Trade to Cancel") # Tag order later response = ticket.Cancel("Canceled SPY Trade") # Use order response object to read status if response.IsSuccessful: self.Debug("Order successfully canceled")
.
we highly recommend you include a slippage model in your algorithm. Slippage is the difference between the expected and final fill prices of a trade.
.
By default, transaction fees are modelled from Interactive Brokers Brokerage rates. These models are customizable by setting a new FeeModel
.
.
This is a quick way to set up a portfolio with a set of weights for assets. If you already have holdings, you may want to liquidate the existing holdings first to free up buying power.
# Allocate 50% of buying power to IBM via market orders. self.SetHoldings("IBM", 0.5) # Allocate 50% of portfolio value to IBM, but liquidate other holdings before starting self.SetHoldings("IBM", 0.5, True)
.
The portfolio variant of SetHoldings was designed to do this operation for you by accepting an array of PortfolioTarget objects.
If you already have holdings, the LEAN engine will calculate the delta-order required to meet your new target. When required, positions will be scaled down before other positions are scaled up in size.
# Purchase a portfolio of targets, processing orders intelligently. self.SetHoldings([PortfolioTarget("SPY", 0.8), PortfolioTarget("IBM", 0.2)])
.
The portfolio variant of SetHoldings was designed to do this operation for you by accepting an array of PortfolioTarget objects.
If you already have holdings, the LEAN engine will calculate the delta-order required to meet your new target. When required, positions will be scaled down before other positions are scaled up in size.
# Purchase a portfolio of targets, processing orders intelligently. self.SetHoldings([PortfolioTarget("SPY", 0.8), PortfolioTarget("IBM", 0.2)])
.
# Calculate the fee adjusted quantity of shares with given buying power quantity = self.CalculateOrderQuantity("IBM", 0.4) self.LimitOrder("IBM", quantity, self.Securities["IBM"].Price)
.
buffer is set to 2.5%. The buffer lives on the algorithm Settings property.
# Adjust the cash buffer from the default 2.5% to 5% self.Settings.FreePortfolioValuePercentage = 0.05
.
# Liquidate all IBM in your portfolio self.Liquidate("IBM") // Liquidate entire portfolio self.Liquidate()
.
.
The algorithm Transactions Manager (SecurityTransactionManager) is a collection of helper methods for quick access to all your orders. It is located in the self.Transactions
property on your algorithm
Using the Transactions Manager, you can retrieve a clone of an order by its Id. Once sent, orders cannot be changed, so the clone of the order is for informational purposes only. To update an order’s properties, you should use an Order Ticket.
# Retrieve a clone of a previously sent order. order = self.Transactions.GetOrderById(orderId)
.
Using the Transaction Manager, you can fetch a list of all open orders for a symbol. This is helpful if you want to update multiple open orders for a specific symbol.
# Retrieve a list of all open orders for a symbol openOrders = self.Transactions.GetOpenOrders(symbol)
.
The Cancel helpers can cancel all open orders, or just those orders related with a specific symbol. The method returns a list of OrderTicket objects.
# Cancel all open orders allCancelledOrders = self.Transactions.CancelOpenOrders() # Cancel orders related to IBM, apply string tag. ibmCancelledOrders = self.Transactions.CancelOpenOrders("IBM", "Hit stop price")
.
def OnOrderEvent(self, orderEvent): order = self.Transactions.GetOrderById(orderEvent.OrderId) if orderEvent.Status == OrderStatus.Filled: self.Log("{0}: {1}: {2}".format(self.Time, order.Type, orderEvent))
status
# Set Limit Order to be good until market close self.DefaultOrderProperties.TimeInForce = TimeInForce.Day self.LimitOrder("IBM", 100, lastClose * decimal.Decimal(.999)) # Set Market Order to be good until noon self.DefaultOrderProperties.TimeInForce = TimeInForce.GoodTilDate(datetime(2019, 6, 19, 12, 0, 0)) self.MarketOrder("IBM", 100)
.
By default, orders remain open until they are canceled (TimeInForce.GoodTilCanceled
). To update the value, set the DefaultOrderProperties.TimeInForce
before placing an order. Doing so will change the default value for all future orders unless reassigned again.
# Set Limit Order to be good until market close self.DefaultOrderProperties.TimeInForce = TimeInForce.Day self.LimitOrder("IBM", 100, lastClose * decimal.Decimal(.999)) # Set Market Order to be good until noon self.DefaultOrderProperties.TimeInForce = TimeInForce.GoodTilDate(datetime(2019, 6, 19, 12, 0, 0)) self.MarketOrder("IBM", 100)
.
If you do not have sufficient capital for the purchase, your order will be rejected. By default, market orders are synchronous and fill immediately.
# Create a Market Order for 100 shares of IBM. marketTicket = self.MarketOrder("IBM", 100) self.Debug("Market Order Fill Price: {0}".format(marketTicket.AverageFillPrice))
.
# Adjust the market fill-timeout to 30 seconds. self.Transactions.MarketOrderFillTimeout = timedelta(seconds=30)
.
# Create a Market Order for 100 shares of IBM asynchronously. self.MarketOrder("IBM", 100, True)
.
Limit orders can be updated
# Purchase 10 SPY shares when its 1% below the current price close = self.Securities["SPY"].Close limitTicket = self.LimitOrder("SPY", 10, close * .99)
.
If the market gaps (jumps in a discontinuous manner) past your stop price, it may be filled at a substantially worse price than the stop price you entered. As such, a stop-loss order is no guarantee your trade will fill at the price you specify.
Stop Market Order StopPrice
, Tag
, and Quantity
can be updated.
# Create Stop Market Order for 1% below current market price. close = self.Securities["SPY"].Close stopMarketTicket = self.StopMarketOrder("SPY", 10, close * 0.99)
.
close = self.Securities["SPY"].Close stopPrice = close * .99 # Trigger stop limit when price falls 1%. limitPrice = close * 1.01 # Sell equal or better than 1% > close. stopLimitTicket = self.StopLimitOrder("SPY", 10, stopPrice, limitPrice)
.
The Market On Open Quantity
and Tag
properties can be updated after creation until the last two minutes before open.
The Market On Open Quantity
and Tag
properties can be updated after creation until the last two minutes before close.
# Create Market Open/Close Orders for 100 shares of IBM marketOpenOrderTicket = self.MarketOnOpenOrder("SPY", 100) # Place Before Open marketCloseOrderTicket = self.MarketOnCloseOrder("SPY", 100) # Place Before Close
.
# Tag an order on creation ticket = self.LimitOrder("SPY", 100, 221.05, "New SPY trade") # Tag order later updateSettings = UpdateOrderFields() updateSettings.Tag = "Our New Tag for SPY Trade" ticket.Update(updateSettings)
.
code:
https://github.com/joeyajames/Python/blob/master/Pandas/Pandas%20-%20Change%20Column%20Names.ipynb
.
.
pandas with datetime
code :
Python Numpy Intro
An introduction to the Python Numpy numerical python library.
The core data structure behind Numpy is the n-dimensional Numpy Array. It is 3x to 10x faster and more memory efficient than Python’s lists because, similar to Java arrays, it uses contiguous blocks of memory, and all elements are the same data type so there is no type checking at runtime. The Numpy library also includes many built-in code-saving mathematical functions that can be performed on an entire array or any slice of an array with a single line of code (ie. no for loops).
Numpy n-dimensional arrays are also sometimes referred to as nd-arrays.
Install Numpy using pip: pip install numpy The convention for importing numpy is import numpy as np.
import numpy as np
Creating a Numpy Array
There are MANY ways to instantiate a numpy array. I covered the most common ones below. Docs here cover more constructors.
You can pass in dtype as an optional argument for any of these. This is especially useful if you want to limit memory usage for a very large array of small integers because int8 and int16 use much less space than the default int32.
In [96]:
a = np.array([1,3,5,7,9,11]) print(a) a = np.arange(1, 12, 2) # (start, stop, step) print(a) a = np.linspace(5, 8, 13) # (start, stop, number of items) print(a) a = np.zeros((4, 2)) print(a) a = np.ones((2, 3), dtype=np.int16) print(a) a = np.full((6,), 88) print(a) a = np.fromstring('25 30 35 40', dtype=np.int, sep=' ') print(a) a = np.array([[1,3,5],[7,9,11]]) print(a) b = np.zeros_like(a) # _like gives you a new array in the same shape as the argument. print(b)
[ 1 3 5 7 9 11] [ 1 3 5 7 9 11] [5. 5.25 5.5 5.75 6. 6.25 6.5 6.75 7. 7.25 7.5 7.75 8. ] [[0. 0.] [0. 0.] [0. 0.] [0. 0.]] [[1 1 1] [1 1 1]] [88 88 88 88 88 88] [25 30 35 40] [[ 1 3 5] [ 7 9 11]] [[0 0 0] [0 0 0]]
Numpy Array Attributes
Get size (number of items), shape (dimensions), itemsize(bytes of memory for each item), and dtype (numpy data type).
See how many bytes of memory space the whole array uses from the product of size and itemsize. See complete list of attributes and methods.
In [97]:
print(a.size) print(a.shape) print(a.ndim) print(a.itemsize) print(a.dtype) print(a.nbytes) # same as a.size * a.itemsize
6 (2, 3) 2 4 int32 24
Indexing and Slicing
Use square brackets to get any item of an array by index. Multi-dimensional arrays can use multiple square brackets.
There are three arguments for slicing arrays, all are optional: [start:stop:step].
If start is left blank it defaults to 0. If stop is left blank it defaults to the end of the array. Step defaults to 1.
In [98]:
print(a) print(a[1]) print(a[0][2]) print(b[2:4]) print(a[:1]) print(a[1:3:2]) print(a[:, 1:2]) # all elements on dimension 0, only element 1 on dimension 1
[[ 1 3 5] [ 7 9 11]] [ 7 9 11] 5 [] [[1 3 5]] [[ 7 9 11]] [[3] [9]]
Reshape, Swap Axes, Flatten
See full list of array manipulation routines.
In [99]:
c = np.arange(-9, -3,).reshape(2,3) print(c) c = c.swapaxes(0,1) print(c) c = c.flatten() print(c)
[[-9 -8 -7] [-6 -5 -4]] [[-9 -6] [-8 -5] [-7 -4]] [-9 -6 -8 -5 -7 -4]
Use dtype to Save Space
Default data types (int32 and float64) are memory hogs. If you don’t need the higher precision you can save a lot of memory space and improve speed of operations by using smaller data types. For large data sets this makes a big difference.
In [100]:
d = np.arange(0,100) print(d.dtype, type(d[1])) print(d.nbytes) d = np.arange(0,100, dtype='int8') print(d.dtype, type(d[1])) print(d.nbytes)
int32 <class 'numpy.int32'> 400 int8 <class 'numpy.int8'> 100
UpCasting, Rounding, Print Formatting
Data type of all Items is upcast to the most precise element.
In [101]:
e = np.array([(1.566666,2,3), (4,5,6)]) print(e.dtype) e = e.round(4) print(e) np.set_printoptions(precision=2, suppress=True) # show 2 decimal places, suppress scientific notation print(e)
float64 [[1.57 2. 3. ] [4. 5. 6. ]] [[1.57 2. 3. ] [4. 5. 6. ]]
Numpy Data Types Available
uint is unsigned int, for positive numbers.
In [102]:
import pprint as pp pp.pprint(np.sctypes)
{'complex': [<class 'numpy.complex64'>, <class 'numpy.complex128'>], 'float': [<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>], 'int': [<class 'numpy.int8'>, <class 'numpy.int16'>, <class 'numpy.int32'>, <class 'numpy.int32'>, <class 'numpy.int64'>], 'others': [<class 'bool'>, <class 'object'>, <class 'bytes'>, <class 'str'>, <class 'numpy.void'>], 'uint': [<class 'numpy.uint8'>, <class 'numpy.uint16'>, <class 'numpy.uint32'>, <class 'numpy.uint32'>, <class 'numpy.uint64'>]}
Reading and Writing to Files
Can use loadtxt, or genfromtxt to load data to load an entire file into an array at once. Genfromtxt is more fault tolerant.
Use savetxt to write an array to file.
In [103]:
f = np.loadtxt('data.txt', skiprows=1, delimiter=',', dtype=np.int32) print(f) print(f.dtype) np.savetxt('data2.txt', f, delimiter=';', fmt='%d', header='a;b;c;d;e;f;g;h;i;j', comments='')
[[9 3 8 7 6 1 0 4 2 5] [1 7 4 9 2 6 8 3 5 0] [4 8 3 9 5 7 2 6 0 1] [1 7 4 2 5 9 6 8 0 3] [0 7 5 2 8 6 3 4 1 9] [5 9 1 4 7 0 3 6 8 2]] int32
In [111]:
g = np.genfromtxt('data.txt', skip_header=1, delimiter=',', dtype=np.int32) print(g)
[[9 3 8 7 6 1 0 4 2 5] [1 7 4 9 2 6 8 3 5 0] [4 8 3 9 5 7 2 6 0 1] [1 7 4 2 5 9 6 8 0 3] [0 7 5 2 8 6 3 4 1 9] [5 9 1 4 7 0 3 6 8 2]]
Mathematical Functions
Numpy has an extensive list of math and scientific functions.
The best part is that you don’t have to iterate. You can apply an operation to the entire array or a slice of an array at once.
In [105]:
print(g > 4) print(g ** 2 - 1)
[[ True False True True True False False False False True] [False True False True False True True False True False] [False True False True True True False True False False] [False True False False True True True True False False] [False True True False True True False False False True] [ True True False False True False False True True False]] [[80 8 63 48 35 0 -1 15 3 24] [ 0 48 15 80 3 35 63 8 24 -1] [15 63 8 80 24 48 3 35 -1 0] [ 0 48 15 3 24 80 35 63 -1 8] [-1 48 24 3 63 35 8 15 0 80] [24 80 0 15 48 -1 8 35 63 3]]
In [106]:
print(g.min()) print(g.max()) print(g.sum()) print(g.mean()) print(g.var()) # variance print(g.std()) # standard deviation print(g.sum(axis=1)) print(g.min(axis=0)) print(g.argmin()) # index of min element print(g.argmax()) # index of max element print(g.argsort()) # returns array of indices that would put the array in sorted order
0 9 270 4.5 8.25 2.8722813232690143 [45 45 45 45 45 45] [0 3 1 2 2 0 0 3 0 0] 6 0 [[6 5 8 1 7 9 4 3 2 0] [9 0 4 7 2 8 5 1 6 3] [8 9 6 2 0 4 7 5 1 3] [8 0 3 9 2 4 6 1 7 5] [0 8 3 6 7 2 5 1 4 9] [5 2 9 6 3 0 7 4 8 1]]
Column Operations
Apply functions only to specific columns by slicing, or create a new array from the columns you want, then work on them.
But Beware that creating a new pointer to the same data can screw up your data if you’re not careful.
In [113]:
print(g[:, 2:3]) print(g[:, 2:3].max()) col3 = g[:, 3:4] # not a copy, just a pointer to a slice of g print(col3.std()) col3 *= 100 # Beware: this is applied to g data print(g)
[[8] [4] [3] [4] [5] [1]] 8 298.607881119482 [[ 9 3 8 70000 6 1 0 4 2 5] [ 1 7 4 90000 2 6 8 3 5 0] [ 4 8 3 90000 5 7 2 6 0 1] [ 1 7 4 20000 5 9 6 8 0 3] [ 0 7 5 20000 8 6 3 4 1 9] [ 5 9 1 40000 7 0 3 6 8 2]]
Numpy Random Functions
In [ ]:
np.set_printoptions(precision=5, suppress=True) # show 5 decimal places, suppress scientific notation h = np.random.random(6) print(h) h = np.random.randint(10, 99, 8) # (low, high inclusive, size) print(h) np.random.shuffle(h) # in-place shuffle print(h) print(np.random.choice(h)) h.sort() # in-place sort print(h)
협정 세계시(UTC)
협정 세계시(UTC)는 1972년 1월 1일부터 시행된 국제 표준시이다.
“UTC"는 보통 "Universal Time Code"나 "Universal Time Convention"의 약어로 사용되기도 하는데,이는 틀린 것이라 한다.실제로 국제 전기 통신 연합은 통일된 약자를 원했지만,영어권의 사람들과 프랑스어권의 사람들은 각각 자신의 언어로 된 약자를 사용하길 원했다.영어권은 CUT(Coordinated Universal Time)을, 프랑스어권은 TUC(Temps Universel Coordonne)를 제안했으며,결국 두 언어 모두 C, T, U로 구성되어 있는 것에 착안해 UTC로 약어를 결정하기로 했다.
UTC는 그리니치 평균시(GMT)로 불리기도 하는데,UTC와 GMT는 초의 소숫점 단위에서만 차이가 나기 때문에 일상에서는 혼용되어 사용한다.기술적인 표기에서는 UTC가 사용된다.
참고로 그리니치 평균시(Greenwich Mean Time, GMT)는,런던(영국의 수도)을 기점으로 하고 웰링턴(뉴질랜드의 수도)을 종점으로 하는 협정 세계시의 빠른 시간이다.
UTC는 그레고리력의 표기를 따른다.1일은 24시간으로 나뉘며, 1시간은 60분으로, 1분은 60초로 나뉘는 것이 보통이나 약간은 가변적이다.UTC의 하루는 보통 86,400초이다. (24시간)
그러나 실제 태양의 자전/공전으로 측정하는 태양시는 86,400초보다 약간 길기 때문에,UTC에서는 때때로 하루의 제일 마지막 1분을 61초로 계산하기도 한다.이렇게 추가되는 초를 윤초라고 하고, 주로 12월 31일이나 6월 30일의 마지막에 추가한다.1972년 이후 25회를 적용했으며,가장 최근에는 2012년 6월 30일 오후 11시 59분 59초(UTC)에서 2012년 7월 1일 0시(UTC)로 넘어갈 때 적용하였다.
그레고리력과 윤년
4로 나뉘어 떨어지는 해는 원칙적으로 윤년이며, 2월 29일을 갖는다.하지만, 100으로 나뉘어 떨어지는 해라면 평년으로 한다.만약, 400으로 나뉘어 떨어진다면 윤년을 유지한다.
ISO 8601
ISO 8601은 날짜와 시간의 표기에 관한 국제 표준 규격이다.정식 명칭은 아래와 같다.Date elements and interchange formats – Information interchange – Representation of dates and times최신 버전인 ISO 8601:2004와 구버전인 ISO 8601:2000, ISO 8601:1988 이 있다.
ISO 8601에 따라 날짜를 기록하는 방법에는 3가지가 있다. – 연월일로 기록하는 방법 – 연과 연중 일수로 기록하는 방법 – 연과 주와 주중 일수로 기록하는 방법이다.
날짜의 표기ISO 8601에는 날짜의 표기에 그레고리력을 따른다.
– 연을 표기할 때는 기원전 1년에 해당하는 0000부터 기원후 9999년에 해당하는 9999까지의 값을 사용할 수 있다. 단, 율리우스력이 사용되던 0000년부터 1582년까지의 값은 정보 교환 시 상호 합의 하에 그레고리력으로 환산해야 한다. 0000년 전이나 9999년 후의 표기도 역시 사용하는 주체간의 상호 합의가 필요하다. 예를 들어, 연도 앞에 빼기표(-)를 붙이면 기원전 1년 이전, 더하기표(+)를 붙이면 기원전 1년 이후를 가리키는 식으로 합의할 수 있다. – 월의 표기는 01부터 12까지의 값을 가지며, 각각 1월부터 12월까지를 나타낸다. – 일의 표기는 01부터 시작하며 달에 따라 28부터 31까지의 값을 가진다. – 연중 일의 표기는 001부터 시작하며 해에 따라 365에서 366까지의 값을 가진다. – 연중 주의 표기는 01부터 시작한다. – 주중 일의 표기는 월요일을 1로 시작하여 순서대로 요일에 숫자를 붙이며, 일요일을 7로 한다.
연월일 표기법 YYYY-MM-DD (확장 형식) 또는 YYYYMMDD (기본 형식)으로 표기한다. 예) 1981-02-22 또는 19810222 : 1981년 2월 22일
연과 연중 일수 표기법 YYYY-DDD (확장 형식) 또는 YYYYDDD (기본 형식)으로 표기한다. DDD는 연중 날의 번호로 1월 1일이 001이며, 12월 31일은 평년은 365, 윤년은 366이 된다. 예) 1981-053 또는 1981053 : 1981년의 53번 째 날
연과 주의 주중 일수 표기법 YYYY-Www-D (확장 형식) 또는 YYYYWwwD (기본 형식)으로 표기한다. ww는 연중 주의 번호로, 해의 첫 주는 01, 마지막 주는 52 또는 53이 된다. 단, 해의 첫 주는 그 해의 첫번째 목요일을 포함한 주로 한다. D는 요일을 나타내며, 월요일이 1, 일요일이 7이다. 예) 1981-W07-7 또는 1981W077 : 1981년의 7번째 주의 일요일
시간의 표기
시간의 표기에는 쌍점을 쓴 hh:mm:ss (확장 형식) 또는 hhmmss (기본 형식)을 사용한다.hh는 시를 나타내며 00부터 24까지의 값을 가지고,mm은 분으로 00부터 59까지의 값을, ss는 초로 00부터 59까지의 값을 갖는다.
날짜와 시간을 함께 표기할 때에는, 날짜와 시간 사이에 T를 넣어 표기한다.
예) 1981-02-22T09:00:00 : 1981년 2월 22일 09:00
시간대의 표기
시간대를 표기할 때에는 Z또는 +/- 기호를 사용한다.
UTC 시간대에서는 시각 뒤에 Z를 붙인다.예) 1981-02-22T09:00Z 또는 19810222T0900Z : UTC 시간대에서의 1981년 2월 22일 오전 9시
UTC 외의 시간대에서는 시각 뒤에 +- hh:mm, +- hhmm, +- hh 를 덧붙여 쓴다.예) 1981-02-22T09:00:00+09:00 : UTC+9 시간대에서의 1981년 2월 22일 오전 9시
+가 붙으면, UTC의 시각보다 더 "빠르다"다는 의미다. 반대로 -는 느리다는 것을 의미하다.예를 들어, 1981-02-22T09:00+09:00 는 1981-02-22T00:00Z 와 동일하다.즉, UTC+9 시간대에서는 오전 9시이지만, UTC 시간대에서는 오전 0시이다.
기간의 표기
기간을 나타낼 때에는 시작일시/종료일시로 표기한다.예) 1981-02-22/2007-09-26 1981-02-22T09:00:00+09:00/2007-09-26T17:00:00+09:00
RFC 3339 Date Formats
ISO8601을 인터넷 프로토콜로 어떻게 다룰 것인지를 규정한 RFC 이다.ISO8601과 거의 비슷하며, 약간의 차이만 있을 뿐이다.예를 들면, RFC 3339에서는 ’T’의 생략을 허용하지 않고, 날짜와 시간 사이의 공백을 허용한다.대부분의 경우, 이 둘을 상세하게 분리해서 생각하지 않아도 된다.
참고:- UTC 위키– 그레고리력 위키– ISO 8601 위키– 타임존 맵 위키– RFC 3339