Original (English)

Options, Futures, FOPs

The following functions can be used for selecting, analyzing, and trading options, futures, and options on futures (FOPs). Since they have additional parameters, namely type, strike, and expiration, options trading is a bit more complex than trading the underlying. For a brief introduction to options trading, read the Black Book chapter 8, or visit Financial Hacker.

contractUpdate (string Name, int Handle, int Mode): int

Loads a new contract chain of type Mode (see below) for the current underlying and the current day. The contract chain contains all options, futures, or FOP contracts available at a certain date. It is required for all the subsequent contract functions and for entering or exiting contract positions.
  Contract chains are only loaded when the LookBack period is over and real trading begins. They are loaded individually per asset and can be directly accessed with the Contracts pointer. Chains are automatically sorted at loading: first by expiration date, then by strike. This allows fast finding a certain option or combo. NumContracts is set to the number of contracts in the chain, which is also returned. If no contract chain for the current or given time is found, 0 is returned.
  In [Test] or [Train] mode the chain is either read out of a contract chain file given by Name.t8 at or before the current time, or from a previously loaded dataset of contracts when its Handle is nonzero. Name can contain month or day numbers for monthly or daily historical contract files. If Name is 0, the current asset name is used. If the global Now variable is nonzero in [Test] or [Train] mode, it is used for filtering contracts instead of the current time. ContractRow is set to the row of the first found contract in the dataset, which allows to load extra data, such as greeks, from a second parallel dataset.
  In [Trade] mode the chain for the symbol Name is either downloaded from the broker API, or - when Handle is nonzero - filled from a previously loaded dataset with no date/time filtering. If Name is 0, the current asset name is used. For contracts that are no US stocks or traded on multiple exchanges, Name should be a symbol with exchange, currency, and for futures the expiration date (e.g. "N225-FUT-20220609-225-OSE.JPN-JPY"). For limiting the chain to a particular trading class, use the SET_CLASS command. 

contractRecord (string Name, var MinStrike, var MaxStrike, int MinDays, int MaxDays)

Appends the current contract chain to the begin of the .t8 contract history file in [Trade] mode. This allows recording live contract chains for re-training or other purposes. The prices of all recorded contracts are loaded from the broker API. Because loading contract prices can take a long time (up to 10 seconds per option contract with the IB API), the strike range and life time can be limited with the MinStrike, MaxStrike, MinDays, MaxDays parameters. Only contracts that fall into the limits and have a nonzero price are recorded. If the limits are 0, prices for the whole chain are loaded. Example: contractRecord(0,priceClose()-50,priceClose()+50,1,70); appends all contracts within a +/-50 strike range and up to 70 days expiration at the begin of the .t8 file of the current asset.

contract (int Type, int Expiry, var Strike): CONTRACT*

Selects the option or future contract from the current option chain that matches exactly the given Type (including FUTURE or EUROPEAN), Expiry date, and Strike value. Returns a CONTRACT pointer to the found contract, or 0 when no such contract was found. If a contract is selected, enterLong and enterShort will buy or write (sell short) the contract instead of the underlying asset. The function sets up ContractStrike, ContractExpiry and other contract variables, and sets ContractRow to the row of the selected contract in the historical dataset or in the options chain. Calling asset(), contractUpdate(), or contract(0,0,0) deselects the contract and allows again trading with the underlying.

contract (int Type, int Days, var Strike): CONTRACT*

As above, but selects the option or future contract that has an expiration of at least the given minimum life time in Days and strike closest to the given Strike value. Returns the CONTRACT pointer, or 0 when no contract with matching Type, at least Days life time, and a strike closer than 10% to Strike was found. 

contract (int N): CONTRACT*

As above, but selects the Nth contract from the current contract chain, where N = 1..NumContracts. If N = 0, the currently selected contract is deselected in order to allow trading with the underlying.

contract (CONTRACT*): CONTRACT*

As above, but selects directly the given option or future contract, and does not alter ContractRow.

contract (TRADE*): CONTRACT*

As above, but selects the contract from a contract trade. Returns 0 if no contract for this trade was found, which can happen at the expiration day or when the chain was not updated. Otherwise trade variables and contract variables are available for the trade and contract. 

contractNext (int Type, int Expiry, var Strike): CONTRACT*

As above, but selects and returns the option or future contract with the Type and Expiry, but the next-higher strike than the given Strike value. If Strike is negative, selects and returns the contract with the next-lower strike value. 

contractFind (int Type, int Days, var Find, int N): CONTRACT*

contractFind (int Type, int Days, var Find, int N, var MinStrike, var MaxStrike): CONTRACT*

contractFind (int Type, int Expiry, var Find, int N): CONTRACT*

contractFind (int Type, int Expiry, var Find, int N, var MinStrike, var MaxStrike): CONTRACT*

As above, but selects the option or future contract with the given Type, closest to the given minimum life time in Days, and a parameter closest to the given Find value. The parameter can be selected with N: 1 = ask, 2 = bid, 3 = fVal, 4 = fVol, 5 = fUnl, 6 = strike, 7 = strike distance from the underlying. The strike range can be optionally limited to MinStrike and MaxStrike for speeding up the function. Returns a CONTRACT pointer, or 0 when no contract was found. If a selected parameter is not yet available, such as ask, bid, or underlying price in live trading, it is automatically retrieved from the broker API. Depending on the number of contracts that match the expiration and strike range, this function can then take a long time (up to 10 seconds per contract) on the first call in live trading after loading a new contract chain. Subsequent calls are faster.

contractDays (CONTRACT*): var

contractDays (TRADE*): var

Returns the fractional number of calendar days until contract or trade expiration (see ExpiryTime). Returns a negative number when the expiration time is in the past. Note that the exact time to expiration depends on the time zone and market close time of the exchange where the contract is traded, so adapt ExpiryTime to your exchange when the exact life time in hours and minutes is needed. Note that many exchanges have restrictions to trading contracts at their expiration day.

contractPrice (CONTRACT*): var

contractPrice (TRADE*): var

Selects the contract and updates the current ask, bid, and underlying price, fill amount, trade profit, either from the broker API, or from historical data by the last contractUpdate call. Only valid as long as the contract is not expired. Returns the bid/ask mid price per underlying unit. Updating contract prices can be slow, depending on broker, Some broker plugins, such as IB, support a 'fast mode' by brokerCommand(SET_PRICETYPE,8); this can remarkably speed up the price update. For retrieving the underlying price in live trading, the GET_UNDERLYING command is used; for updating the fill amount, the BrokerTrade function is used and must be supported by the API. If the contract is not traded or the market data not subscribed, the function returns 0. Contract prices of open positions are automatically updated at any bar. If the underlying price is not available, it is updated from the current asset price. The underlying price is automatically copied to all contracts of the current chain with the same expiration date.  

contractUnderlying (): var

Returns the unadjusted underlying price, in [Trade] mode from the current contract, otherwise from the fUnl element of the first contract of the chain. If the underlying price is not available, returns the price of the currently selected asset.Make sure with contractUpdate and contractPrice that the contract is up to date. Note that FOPs have no common underlying price, but fUnl depends on the expiration and can be different for any contract. Source code in contract.c.

contractPosition (TRADE*): int

Returns the current number of open lots or open contracts of the given trade (negative values for a short position). Can be used for determining if a certain contract was expired or exercised by the broker. In live trading the GET_POSITION command must be supported by the broker API, and no other trades with the same contract type, strike, and expiry must be opened.

contractCheck (TRADE*, int Mode): int

Checks the option position on the broker account in live [Trade] mode. If it is still open, returns the total number of open contracts (negative for a short position). Otherwise it checks for an open position of the underlying, and returns the position size. If Mode is at 1 and no open contract was found, the trade is automatically closed with a "Lapsed" message. If Mode is at 3 and an underlying position was found, it is sold at market. Mode = 3 thus replicates the backtest behavior of expired options. The function can be called regularly in a for(open_trades) loop for keeping the positions between broker and strategy in sync. The GET_POSITION command must be supported by the broker API, and no other trades with the same contract type, strike, expiry, and underlying must be opened.

contractRoll (TRADE*, int Days, var Strike, function TMF): TRADE*

Rolls a closed option or future contract by opening a duplicate with the same type, volume, stop loss and profit distances, the given number of Days until expiration, the given Strike (0 for using the previous strike) and an optional trade management function. Returns a pointer to the new trade, or 0 if the contract could not be rolled. Source code in contract.c.

contractSellUnderlying (): int

Checks in [Trade] mode if any underlying position of the current asset is open, and if so, sells it at market. Returns the number of lots, or 0 when no underlying position was found. Source code in contract.c.

contractExercise (TRADE*)

Exercises an option contract. In the backtest, the option is closed at its intrinsic price (see remarks). In live trading, an order to exercise the option is sent to the broker. It is normally not immediately executed, but pending. Use contractCheck() for closing the trade and selling the underlying as soon as the order was executed. Don't call this function for European options before expiration, or for options that are not in the money.
 

contractVal (CONTRACT*, var Price, var HistVol, var Dividend, var RiskFree, var* Delta, var* Gamma, var* Vega, var* Theta, var* Rho): var

Returns the theoretical value and optionally the greeks of the given option contract at the given unadjusted Price of the underlying. Type, fStrike, and Expiry of the contract must be set; the other parameters don't matter. Expiry can be either an expiration date in the YYYYMMDD format, or alternatively the number of calendar days until expiration. HistVol is the underlying annual volatility of the log returns, f.i. by Volatility or VolatilityOV (usually over 20 days). Dividend is the continuous annual dividend yield per year of the underlying, as a fraction in the 0..1 range. RiskFree is the annual risk-free yield as a fraction in the 0..1 range, f.i. by yield()/100.
  Delta is the impact of an underlying price change on the option value, in the 0..1 range for calls and 0..-1 for puts. Gamma is the impact on Delta. Vega is the impact of a change of the underlying volatility, Theta is the impact of a change of the expiration time, and Rho is the impact of a change of the risk-free yield.
  The function uses R and the RQuantLib package; both must be installed (see remarks below). Source code in contract.c.

contractVol (CONTRACT*, var Price, var HistVol, var Value, var Dividend, var RiskFree): var

Returns the implied volatility (IV) of the given option contract with the given Value. For the parameters, see contractVal. The function uses R and the RQuantLib package; both must be installed on the trading PC (see remarks below). Source code in contract.c. The implied volatility is an estimate of the future volatility of the underlying, based on the current option parameters. If the contract has no value or if the strike price is too far or on the wrong side of the asset price, the function returns 0

contractDelta (int Type, int Days, var Price, var HistVol, var RiskFree, var Strike): var

Returns the theoretical delta of a contract of given Type with the given Days until expiration, unadjusted underlying Price, volatility HistVol, RiskFree yield rate, and Strike. Uses the formula Delta = cdf((ln(Price/Strike) + (r + (sigma^2)/2) * T) /(sigma * sqrt(T))). Source code in contract.c. Delta is the first derivative of the option value with respect to the underlying price, and can be used as a proxy of the probability to expire in the money. Note that some platforms and brokers use individual methods for calculating HistVol and thus produce different Delta values for the same contracts.

contractStrike (int Type, int Days, var Price, var HistVol, var RiskFree, var Delta): var

Returns the theoretical strike value of a contract of given Type with the given Days until expiration, unadjusted underlying Price, volatility HistVol, RiskFree yield rate, and Delta. Uses the formula Strike = Price * exp(-qnorm(Delta) * sigma * sqrt(T) + (r + (sigma^2)/2) * T). If a positive Delta is entered for a put, it is converted to the equivalent negative delta, so the same Delta value can be used for selecting put and call contracts. Source code in contract.c.

contractIntrinsic (CONTRACT*, var Price): var

contractIntrinsic (TRADE*, var Price): var

Returns the intrinsic value of the option contract per underlying unit at the given Price of the underlying. The intrinsic value of a call option is the difference between price and strike; for put options it's the difference between strike and price. A positive difference means that the option is in the money, a negative difference means it's out of the money. Type and fStrike of the contract or trade must be set; the other parameters don't matter. Source code in contract.c.

contractProfit (CONTRACT*, var Price, var Premium): var

Returns the profit per underlying unit of a contract sold or purchased at the given Premium when expiring at the given underlying Price. Premium is positive for sold, negative for bought contracts. Type and fStrike of the contract must be set; the other parameters don't matter. Trading costs are not included. The calculation of profit or loss is described in the remarks below. Source code in contract.c.

contractMargin (CONTRACT*, int AssetType): var

Calculates the margin cost of the given non-covered short put/call contract for the given AssetType (the margin of long contracts is simply their ask price). Uses the margin formula on the Interactive Broker's US Options Margin Requirements page. Source code in contract.c.

contractLetter (int AssetMonth): string

Returns the letter assigned to the given expiration month (F Jan, G Feb, H Mar, J Apr, K May, M Jun, N Jul, Q Aug, U Sep, V Oct, X Nov, Z Dec). Source code in contract.c.
  

contractPrint ()

Exports the current contract chain to a Data\*.csv file, for diagnostics purposes,

contractPrint (CONTRACT*)

Prints the given contract parameters to the log file for diagnostics purposes, in the order Date, Type, Expiry, Strike, Underlying, Ask, Bid, fVal, fVol. 

plotContract (int N, CONTRACT*, var HistVol, var Min, var Max, int Days, int Modus)

Plots the payoff diagram of N contracts (negative for selling) with volatility HistVol from price Min to price Max. Modus 0 initializes the plot and plots a zero line, Modus 1 plots the diagram at expiration, Modus 2 at the given Days into the lifetime (RQuantLib required), and Modus 3 plots the Delta. Type, strike, ask, bid, and expiry in days must be set in the CONTRACT struct. Source code in contract.c; usage example in PayOff.c.

 

yield(): var

Helper function, returns the current yield rate of 3-months US treasury bills in percent. Can be used as a proxy of the risk-free interest for calculating the values of option contracts (divide it by 100 for using it in contractVal or contractVol). Works in backtest as well as live trading. Uses the dataFromQuandl function. Zorro S required for Quandl data access; enter your Quandl key in the QuandlKey field in Zorro.ini. Source code in contract.c.

yieldCSV(): var

As above, but gets the current yield rate from an already-downloaded treasure history in History\FRED-DTB3.csv.

initRQL(): int

Helper function that initalizes RQuantLib. Call this in the INITRUN when contractVal or contractVol are used.

 

Parameters:

Name The name of the underlying, f.i. "ES" or "SPY", or the symbol - if different to the name - in live trading, or 0 for using the name or symbol of the current asset. For contract chains in backtest mode, use the name of the current .t8 file for loading monthly or daily files.
Handle A number from 1...800 that identifies a previously loaded dataset containing a CONTRACT list with historical options data; or 0 for automatically loading content from a historical file or from the broker API.
Mode PUT|+CALL for options, FUTURE for futures, PUT+CALL+FUTURE for options on futures.
Type The exact contract type to match, a combination of PUT, CALL, FUTURE, EUROPEAN, BINARY (f.i. PUT+EUROPEAN), plus the following optional flags:
+ONLYW3 - select only contracts that expire at the 3rd Friday, i.e. between the 16th and the 21th of the month.
+ONLYMATCH - select only contracts that exactly match the expiration date.
AssetType 1 for a currency, 2 for an index, 3 for stocks and ETFs. The margin for futures must be individually calculated.
Days The minimum number of calendar days until expiration. The closest expiration date will be selected.
Expiry The expiration date in the YYYYMMDD format.
Strike Option strike price, or 0 for futures.
Delta First derivative of the option value with respect to the underlying price. Determines the impact of an underlying price change on the option value, and can serve as a proxy of the probability to expire in the money. 0..1 for calls and 0..-1 for puts.
HistVol The historical annualized volatility of the underlying asset, as a fraction, f.i. 0.2 for 20%. Normally calculated with the Volatility or VolatilityOV indicators from the last 20 days. For the calculation of greeks, implied volatility is often used instead of historical volatility.
Dividend The annual dividend yield of the underlying, as a fraction, f.i. 0.02 for 2% dividend yield.
RiskFree The risk-free interest rate, as a fraction, f.i. yield()/100.
Value The value of the option for determining the implied volatility.
TRADE* The pointer of an option or future trade. Use ThisTrade for the trade pointer in a TMF or trade enumeration loop.

Remarks:

  • contract.c must be included for all contract functions. The underlying asset must be selected and a contract chain must be loaded before calling a contract function.
  • The contractVal and contractVol functions also require R with the Rcpp and RQuantLib packages that you can install from the Cran repository, either with the install.packages command or from the menu when using RStudio. For checking if everything is working, call a library function from the R console, like this:

    require('RQuantLib')
    AmericanOption('put', underlying=100, strike=100, dividendYield=0.02, riskFreeRate=0.01, maturity=0.5, volatility=0.4, engine='CrankNicolson')
    
    Concise summary of valuation for AmericanOption
      value  delta  gamma  vega theta rho divRho
    11.4122 -0.4463 0.0139  NA   NA   NA   NA
    

    RQuantLib must be initialized in the INITRUN by calling initRQL The current RQuantLib version tends to crash when a function is called with bad parameters, like negative volatility, or with a value that contradicts the strike and spot price, or with too long strike distances. After a crash, all RQuantLib functions return 0.
  • Contract chains loaded from historical data normally contain prices, underlying, and optional data such as delta. Chains downloaded from the broker normally contain only strikes and expirations. Since loading option chains can take a long time (~15 minutes for long chains with some brokers), and expirations and strikes don't change intraday, it is recommended to call contractUpdate in live trading only once per day, preferably outside market hours. Prices can then be updated with contractPrice; prices of open trades are automatically updated. In test and training, contractUpdate should be called at any bar for updating the prices.
  • Some brokers are reported to return already-expired contracts in their contract chain. Make sure to check the expiration date when selectiung a contract.
  • High resolution options data can be split in monthly or daily .t8 files and loaded per script in a dataset that is then fed to the contractUpdate function (see example).
  • Entry, Stop, and TakeProfit limits also work for trading options and futures. They must be given as an absolute price limit to the ask price of the contract, not as a distance. When an exit limit is hit, the contract is sold at market. Of course the usefulness of stop/profit limits for option values is arguable.
  • For entering a trade, make sure that a contract is selected. Otherwise you would unwillingly open a position of the underlying. Check with contractPrice() that a nonzero ask or bid price, depending trade direction, is available for the contract or for all contracts of a combo. Set the Multiplier correctly, otherwise the backtest result will be wrong. Some brokers also require the Exchange to be set. The correct multiplier of an option or future contract can be found on the asset description on the website of the broker or the exchange. For stocks, the multiplier is normally 100.
  • Underlying prices downloaded with the assetHistory function are normally split and dividend adjusted and therefore won't match strike prices. You can use the UNADJUSTED flag for downloading unadjusted prices instead. But often you'll need both sorts of prices in an options trading system, unadjusted prices for calculating greeks or determining strikes, and adjusted prices for historical volatility and for indicators. The usual convention is having adjusted prices in .t6 history and using the contractUnderlying() function for the unadjusted prices.
  • When an option is closed, either by an exit command or by reaching a stop or profit target, it is automatically sold back or covered at the current ask or bid price. If no market price is available, the option stays open until the next exit command or until it expires or is exercised. Options and futures can only be traded, and their prices can only be downloaded when the market is open. Do not send enter, exit, or exercise option positions outside market hours.
  • If an option expires or is exercised, a position of the underlying can appear. For live trading, the contractCheck command can check if an underlying position is open, and sell it automatically. In the backtest, underlying positions opened by expired or exercised options are immediately sold at market, and the profit or loss is booked on the account.
  • For calculating profit/loss of an option, the following algorithm is used:
    - A call is assumed in the money when the strike is below the bid price (i.e. ask - spread); a put is assumed in the money when the strike is above the ask price.
    - A long call or short put in the money buys the underlying at strike price, and sells it at bid price. The difference is added to or subtracted from the account.
    - A long put or short call in the money sells the underlying at strike price, and buys it back at ask price. The difference is added to or subtracted from the account.
    - For a long position the premium is subtracted from the account, for a short position the premium is added to the account.
  • An example for finding the parameters of commodity FOPs. Go to https://www.cmegroup.com/trading and enter the name, for instance "Natural Gas", in the search field. A list of symbols will appear (otherwise you have to look it up at a different exhange). Select the symbol with the high trade volume, in the example "NG". Click on the link under Product Name. Then select Contract Specs. The multiplier (10,000 for NG) is the Contract Unit, the pip size of the underlying is the Minimum Price Fluctuation ($0.001). Pip cost are the $0.001 in your account currency. Under Quotes you can see the current price per underlying unit ($3.146). Check if the price is in cents or dollars (see below). Under Margins you can see that the most recent November 2018 contract has $1950 maintenance margin. That's $0.195 margin cost per underlying unit. Now look up the symbol in your broker platform and check its ticker name. Check also if your broker uses the same margin. That's all you need to add the underlying to your asset list. The line will look like this (on an USD account): NG,3.146,0.001,0,0,0.001,0.001,0.195,0,1,0.002,NG.
  • Futures and options on futures (FOPs) sometimes have prices sometimes in cents, sometimes in dollars, sometimes mixed in any possible combination of historical and live data. For trading with FOPs, check historical data and broker data and determine which prices - ask/bid, strike, underlying - are in cents and which in dollars. This can be different with any future and any broker. Set the Centage variable accordingly for using consistent dollar prices in the strategy, charts, and reports.
  • The class or root symbol of a contract can be retrieved in live trading from the first element of a CONTRACT struct: string RootSymbol = (string)MyContract;. Note that this only works in Live mode, as in the backtest the first CONTRACT element is the time.
  • Many broker APIs, for instance IB, do not manage trades, but only positions. Those APIs can not distinguish between an underlying position opened by a normal trade, and a position opened by an exercised option. This must be considered in the script. Buying long and short the same contract with the same strike and expiry is treated as two different trades by Zorro, but as two positions that cancel each other by most brokers.
  • Some broker APIs, for instance IB, need a certain "recovery time" after downloading an options chain before downloading the next chain. When downloading chains of multiple assets, wait some seconds between contractUpdate calls.
  • Use the exit command if you want to close a contract by selling it or buying it back. On NFA accounts, functions like contractPosition or contractCheck only check the net position of open option trades, and will return wrong results when several long and short positions of the same contract are open. For the same reason, multiple scripts can trade options on the same NFA account only when they don't open the same contracts.
  • Slippage is not simulated for options. Commission and margin are set by default to the commission and margin of the underlying in the asset list, multiplied with the Multiplier. Commission is reduced by 50% when an option expires worthless. Since most brokers have different and complex calculation methods for option margins, the default margin is just an approximation. For better accuracy, use the contractMargin or comboMargin functions or calculate Commission and MarginCost parameters explicitly in the script prior to entering a trade. For instance when trading vertical spreads, margin cost is often determined by the strike price difference, therefore set MarginCost = 0.5 * (Strike1-Strike2) before opening the two positions. The margin cost of covered contracts is usually 0. The margin requirements by IB can be found on https://www.interactivebrokers.com/en/index.php?f=24176.
  • When optimizing option strategies, the default objective function is not the ideal performance measure for options. Better is dividing the total profit by the required margin. Example:
    var objective()
    {
      if(!NumWinTotal && !NumLossTotal) return 0;
      return (WinTotal-LossTotal)/MarginMax;
    }
    
  • Phantom trades and virtual hedging are not used for contracts. Options can always be hedged regardless of the Hedge setting.
  • Some historical options before 2014 expired on Saturday; afterwards they expired on Friday. Options with Saturday expiration are treated as if they expired on Friday. The expiration hour can be set up with the ExpiryTime variable.
  • The CONTRACT struct is defined in trading.h. For backtests the following struct elements must be filled in the data set; for futures: time, fAsk, fBid, Expiry, Type; for options: time, fAsk, fBid, fStrike, Expiry, Type. The other CONTRACT elements are optional and for use in the script only.
  • contract(Contracts) selects the first contract in the chain.
  • For calculating the option value, American options are approximated with the Crank-Nicolson method, while European options are calculated with the (much faster) Black-Scholes formula. For short-term options the results of both methods are not very different, so the EUROPEAN flag can be used in such cases even for American options in order to speed up the calculation.
  • The contractVol function is known to terminate the R session when called with unrealistic parameters, such as an unlikely small option value for a high strike-spot difference and short expiration date. This can be tested with the Rrun function ( if(!Rrun()) quit("R terminated!"); ). When the R session is terminated by an exception in the backtest, Zorro must be restarted.
  • For finding the contract with the lowest strike and a particular property, start with the strike price at the current price, then call contract(...) in a loop and modify the strike in steps until the condition is fulfilled. For CALL options increase the strike, for PUT options decrease it.
  • For converting dates from or to the YYYYMMDD format or for finding the 3rd Friday of a month, use the dmy, ymd, and nthDay functions.
  • Several option scripts are included. The TradeOptions script can be used for testing the opening and closing of SPY options via broker API. It only runs at NY market hours and takes about 30 seconds for downloading the option chain at start. The Payoff script can interactively display payoff and delta diagrams of option combinations. The OptionsCalculator script calculates the price and delta of calls and puts, where underlying, strike, and expiration of options can be set up with sliders. Feel free to combine the scripts to your own specialized options tool.

Examples:

// Sell call and put options at 1 stddev of the underlying
// Buy them back 2 days before expiration
#include <contract.c>

void run() 
{
  BarPeriod = 1440;
  BarZone = EST;
  BarOffset = 15*60; // trade at 3 pm Eastern time
  LookBack = 20;
  if(Init) {
    assetList("AssetsIB");
    assetHistory("SPY",FROM_AV|UNADJUSTED);
    brokerCommand(SET_CLASS,"SPYW");
  }
  asset("SPY");
  Multiplier = 100;
 
  if(!NumOpenTotal && !is(LOOKBACK)) {
    contractUpdate(Asset,0,PUT|CALL);
    vars Close = seriesC();  
    int DTE = 6*7; // look for 6-week contracts
    var Strangle = StdDev(Close,20);
    CONTRACT* Call = contract(CALL,DTE,Close[0] + Strangle);
    CONTRACT* Put = contract(PUT,DTE,Close[0] - Strangle);
    if(Call && Put) { // open single positions, no combo
      contract(Call); enterShort();
      contract(Put); enterShort();
    }
  }

// Check expiration and buy them back when in the money
  for(open_trades) 
  {
    if(contractDays(ThisTrade) <= 2
      && contractIntrinsic(ThisTrade,Close[0]) > 0)
         exitTrade(ThisTrade);
  }
}
// Load high res contract chains from daily files like "SPY_20210505.t8"
if(day(0) != day(1)) { // new day?
  if(Live) // load a new contract chain without prices
    contractUpdate(0,1,CALL|PUT);
  else // load a new t8 file with prices
    dataLoad(1,strf("History\\%s_%04d%02d%02d.t8",Asset,year(0),month(0),day(0)),9);
}
if(!Live) // in the backtest, update prices at any bar
  contractUpdate(0,1,CALL|PUT);
// Example script for converting EOD options data to .t8:
// Format: underlying symbol, exchange, date MMDDYYYY, adj close, option symbol, expiry MMDDYYYY, strike, Call/Put, American/European, ask, bid, volume, open interest, close
// Sample: "TLT,NYSEArca,04/10/2015,129.62,TLT   150410C00112500,04/10/2015,112.5,C,A,17.3,16.2,0,0,129.62"

string Format = ",,%m/%d/%Y,,,i,f,s,s,f,f,f,f,f";

void main() 
{
// first step: parse the CSV file into a dataset
  int Records = dataParse(1,Format,FILENAME);
  printf("\n%d Records parsed",Records);
// second step: convert the raw data to the final CONTRACT format
  for(i=0; i<Records; i++) 
  {
    CONTRACT* C = dataAppendRow(2,9);
    C->time = dataVar(1,i,0);
    string PC = dataStr(1,i,3);
    string EA = dataStr(1,i,4);
    C->Type = ifelse(*PC == 'P',PUT,CALL) + ifelse(*EA == 'E',EUROPEAN,0);
    int Expiry = dataInt(1,i,1); 
    C->Expiry = 10000*(Expiry%10000) + Expiry/10000; // MMDDYYYY -> YYYYMMDD
    C->fStrike = dataVar(1,i,2);
    C->fAsk = dataVar(1,i,5);
    C->fBid = dataVar(1,i,6);
    C->fVol = dataVar(1,i,7);
    C->fVal = dataVar(1,i,8); // open interest
    C->fUnl = dataVar(1,i,9);
    if(!progress(100*i/Records,0)) break; // show a progress bar
  }
  dataSort(2);
  dataSave(2,"History\\MyOptions.t8");
}

See also:

enterLong/Short, exitLong/Short, Quandl bridge, date functions, contract variables, contractCPD, combo, workshop 8

 

► latest version online

Übersetzung (Deutsch)

Optionen, Futures, FOPs

Die folgenden Funktionen können zum Auswählen, Analysieren und Handeln von Optionen, Futures und Options on Futures (FOPs) verwendet werden. Da sie zusätzliche Parameter wie Typ, Strike und Verfall besitzen, ist der Optionshandel etwas komplexer als der Handel des Basiswertes. Für eine kurze Einführung in den Optionshandel lies Kapitel 8 im Black Book oder besuche Financial Hacker.

contractUpdate (string Name, int Handle, int Mode): int

Lädt eine neue Kontraktkette des Typs Mode (siehe unten) für den aktuellen Basiswert und den aktuellen Tag. Die Kontraktkette enthält alle verfügbaren Optionen, Futures oder FOP-Kontrakte zu einem bestimmten Datum. Sie wird für alle weiteren contract-Funktionen und für das Öffnen oder Schließen von Kontraktpositionen benötigt.
  Kontraktketten werden erst geladen, wenn die LookBack-Periode beendet ist und der reale Handel beginnt. Sie werden pro Asset individuell geladen und können direkt über den Contracts-Pointer angesprochen werden. Beim Laden werden die Ketten automatisch sortiert: zuerst nach Verfallsdatum, dann nach Strike. Dies ermöglicht ein schnelles Auffinden einer bestimmten Option oder Kombination. NumContracts wird auf die Anzahl der Kontrakte in der Kette gesetzt, welcher Wert auch zurückgegeben wird. Wenn keine Kontraktkette für die aktuelle oder angegebene Zeit gefunden wird, liefert die Funktion 0.
  Im [Test] oder [Train] Modus wird die Kette entweder aus einer Kontraktkettendatei namens Name.t8 geladen, die zum aktuellen oder früheren Zeitpunkt existiert, oder aus einem zuvor geladenen Datensatz mit Kontrakten, wenn Handle ungleich null ist. Name kann Monats- oder Tagesangaben für monatliche oder tägliche historische Kontraktdateien enthalten. Ist Name 0, wird der aktuelle Asset-Name verwendet. Wenn die globale Now-Variable im [Test] oder [Train] Modus ungleich null ist, wird sie zum Filtern der Kontrakte anstelle der aktuellen Zeit verwendet. ContractRow wird auf die Zeile des ersten gefundenen Kontrakts im Datensatz gesetzt, was das Laden zusätzlicher Daten wie Greeks aus einem zweiten parallelen Datensatz ermöglicht.
  Im [Trade] Modus wird die Kette für das Symbol Name entweder von der Broker-API heruntergeladen oder - wenn Handle ungleich null ist - aus einem zuvor geladenen Datensatz ohne Zeitfilterung gefüllt. Ist Name 0, wird der aktuelle Asset-Name verwendet. Für Kontrakte, die keine US-Aktien sind oder auf mehreren Börsen gehandelt werden, sollte Name ein Symbol mit Börse, Währung und bei Futures dem Verfallsdatum sein (z.B. "N225-FUT-20220609-225-OSE.JPN-JPY"). Um die Kette auf eine bestimmte Trading-Klasse zu begrenzen, verwende den SET_CLASS-Befehl. 

contractRecord (string Name, var MinStrike, var MaxStrike, int MinDays, int MaxDays)

Hängt die aktuelle Kontraktkette am Anfang der .t8-Kontrakthistorie im [Trade] Modus an. Dies ermöglicht das Aufzeichnen von Live-Kontraktketten für Re-Training oder andere Zwecke. Die Preise aller aufgezeichneten Kontrakte werden von der Broker-API geladen. Da das Laden der Kontraktpreise (bei der IB-API bis zu 10 Sekunden pro Optionskontrakt) lange dauern kann, können mit den Parametern MinStrike, MaxStrike, MinDays, MaxDays der Strike-Bereich und die Laufzeit begrenzt werden. Nur Kontrakte, die in diese Grenzen fallen und einen vom Broker gelieferten Nicht-Null-Preis haben, werden aufgezeichnet. Wenn die Grenzen 0 sind, werden Preise für die gesamte Kette geladen. Beispiel: contractRecord(0,priceClose()-50,priceClose()+50,1,70); hängt alle Kontrakte mit +/-50 Strike-Bereich und einer Laufzeit bis zu 70 Tagen am Anfang der .t8-Datei des aktuellen Assets an.

contract (int Type, int Expiry, var Strike): CONTRACT*

Wählt den Options- oder Future-Kontrakt aus der aktuellen Optionskette aus, der genau zu dem gegebenen Type (einschließlich FUTURE oder EUROPEAN), Verfallsdatum Expiry und Strike-Preis passt. Gibt einen Zeiger auf CONTRACT zurück, oder 0, wenn kein solcher Kontrakt gefunden wurde. Wenn ein Kontrakt ausgewählt ist, werden durch enterLong und enterShort anstelle des Basiswertes der ausgewählte Kontrakt gekauft oder geschrieben (Short-Verkauf). Die Funktion setzt ContractStrike, ContractExpiry und andere Kontraktvariablen, sowie ContractRow auf die Zeile des ausgewählten Kontrakts im historischen Datensatz oder in der Optionskette. Ein Aufruf von asset(), contractUpdate() oder contract(0,0,0) hebt die Kontraktauswahl auf und erlaubt wieder das Handeln des Basiswertes.

contract (int Type, int Days, var Strike): CONTRACT*

Wie oben, jedoch wird der Options- oder Future-Kontrakt gewählt, der mindestens die angegebene Laufzeit in Days hat und dessen Strike dem gegebenen Strike am nächsten liegt. Gibt den CONTRACT-Zeiger zurück, oder 0, wenn kein Kontrakt mit passendem Type, mindestens Days Laufzeit und einem Strike, der dem Ziel-Strike um maximal 10% abweicht, gefunden wurde. 

contract (int N): CONTRACT*

Wie oben, jedoch wird der N-te Kontrakt aus der aktuellen Kontraktkette ausgewählt, wobei N = 1..NumContracts ist. Ist N = 0, wird der aktuell ausgewählte Kontrakt abgewählt, sodass wieder der Basiswert gehandelt werden kann.

contract (CONTRACT*): CONTRACT*

Wie oben, jedoch wird direkt der übergebene Options- oder Future-Kontrakt ausgewählt, ohne ContractRow zu verändern.

contract (TRADE*): CONTRACT*

Wie oben, jedoch wird der Kontrakt aus einem bereits existierenden Kontrakt-Trade ausgewählt. Gibt 0 zurück, wenn für diesen Trade kein Kontrakt gefunden wurde (z.B. am Verfallstag oder wenn die Kette nicht aktualisiert wurde). Andernfalls stehen Trade-Variablen und Kontraktvariablen für Trade und Kontrakt zur Verfügung. 

contractNext (int Type, int Expiry, var Strike): CONTRACT*

Wie oben, jedoch wird der Options- oder Future-Kontrakt ausgewählt und zurückgegeben, dessen Type und Expiry übereinstimmen, aber dessen Strike oberhalb des angegebenen Strike-Werts liegt. Wenn Strike negativ ist, wird stattdessen der nächstniedrigere Strike zurückgegeben. 

contractFind (int Type, int Days, var Find, int N): CONTRACT*

contractFind (int Type, int Days, var Find, int N, var MinStrike, var MaxStrike): CONTRACT*

contractFind (int Type, int Expiry, var Find, int N): CONTRACT*

contractFind (int Type, int Expiry, var Find, int N, var MinStrike, var MaxStrike): CONTRACT*

Wie oben, jedoch wird der Options- oder Future-Kontrakt mit dem gegebenen Type ausgewählt, der der angegebenen Mindestlaufzeit Days am nächsten kommt und dessen Parameter am nächsten zum Wert Find liegt. Dieser Parameter wird durch N bestimmt: 1 = ask, 2 = bid, 3 = fVal, 4 = fVol, 5 = fUnl, 6 = strike, 7 = Strike-Abstand zum Basiswert. Der Strike-Bereich kann optional mit MinStrike und MaxStrike begrenzt werden, um die Funktion zu beschleunigen. Gibt einen CONTRACT-Zeiger zurück, oder 0, wenn kein passender Kontrakt gefunden wurde. Wenn ein ausgewählter Parameter noch nicht verfügbar ist, z.B. ask, bid oder der Basiswertpreis im Live-Trading, wird er automatisch von der Broker-API abgerufen. Abhängig von der Anzahl passender Kontrakte (Verfall und Strike-Bereich) kann dieser erste Aufruf im Live-Trading bis zu 10 Sekunden pro Kontrakt dauern, nachdem eine neue Kette geladen wurde. Nachfolgende Aufrufe sind schneller.

contractDays (CONTRACT*): var

contractDays (TRADE*): var

Gibt die Anzahl der Kalendertage (als reelle Zahl) bis zum Ablauf des Kontrakts oder Trades zurück (siehe ExpiryTime). Gibt einen negativen Wert zurück, wenn die Verfallszeit in der Vergangenheit liegt. Beachte, dass die genaue Zeit bis zum Verfall von Zeitzone und Börsenschluss der entsprechenden Börse abhängt, daher passe ExpiryTime an, wenn du eine exakte Laufzeit in Stunden und Minuten benötigst. Beachte auch, dass viele Börsen Handelsbeschränkungen für Kontrakte am Verfalltag haben.

contractPrice (CONTRACT*): var

contractPrice (TRADE*): var

Wählt den Kontrakt aus und aktualisiert den aktuellen Ask-, Bid- und Basiswertpreis, Füllmenge und Trade-Gewinn entweder von der Broker-API oder aus historischen Daten, basierend auf dem letzten Aufruf von contractUpdate. Gültig nur, solange der Kontrakt nicht abgelaufen ist. Liefert den Mid-Preis aus Ask und Bid, bezogen auf die Einheit des Basiswertes. Das Aktualisieren von Kontraktpreisen kann, je nach Broker, langsam sein. Einige Broker-Plugins wie IB unterstützen einen "Fast Mode" durch brokerCommand(SET_PRICETYPE,8);, was das Preisupdate deutlich beschleunigen kann. Um den Basiswertpreis im Live-Trading abzurufen, wird der GET_UNDERLYING-Befehl verwendet; um die Füllmenge zu aktualisieren, wird die BrokerTrade-Funktion genutzt, die von der API unterstützt sein muss. Wenn der Kontrakt nicht gehandelt wird oder keine Marktdaten abonniert sind, gibt die Funktion 0 zurück. Kontraktpreise offener Positionen werden automatisch bei jedem Bar aktualisiert. Wenn der Basiswertpreis nicht verfügbar ist, wird er vom aktuellen Asset-Preis abgeleitet. Der Basiswertpreis wird automatisch auf alle Kontrakte der aktuellen Kette mit demselben Verfallsdatum übertragen.  

contractUnderlying(): var

Gibt im [Trade] Modus den nicht angepassten Basiswertpreis des aktuellen Kontrakts zurück, sonst den fUnl-Wert des ersten Kontrakts der Kette. Ist der Basiswertpreis nicht verfügbar, wird der Preis des aktuell gewählten Assets zurückgegeben. Stelle durch contractUpdate und contractPrice sicher, dass der Kontrakt aktuell ist. Beachte, dass FOPs keinen gemeinsamen Basiswertpreis haben, sondern fUnl abhängig vom Verfallsdatum ist und für jeden Kontrakt unterschiedlich sein kann. Quellcode in contract.c.

contractPosition (TRADE*): int

Gibt die aktuelle Anzahl der offenen Lots oder Kontrakte des übergebenen Trades zurück (negative Werte bei einer Short-Position). Kann verwendet werden, um festzustellen, ob ein bestimmter Kontrakt vom Broker abgelaufen oder ausgeübt wurde. Im Live-Trading muss der Befehl GET_POSITION von der Broker-API unterstützt werden und es dürfen keine anderen Trades mit demselben Kontrakttyp, Strike und Verfall offen sein.

contractCheck (TRADE*, int Mode): int

Prüft im Live-Modus [Trade] die Optionsposition auf dem Broker-Konto. Wenn sie noch offen ist, wird die Gesamtzahl der offenen Kontrakte zurückgegeben (negativ für eine Short-Position). Andernfalls wird geprüft, ob eine offene Position im Basiswert existiert, und deren Positionsgröße wird zurückgegeben. Ist Mode = 1 und kein offener Kontrakt gefunden, wird der Trade automatisch mit der Meldung "Lapsed" geschlossen. Ist Mode = 3 und eine Basiswertposition gefunden, wird diese zum Marktpreis verkauft. Mode = 3 ahmt damit das Backtest-Verhalten abgelaufener Optionen nach. Die Funktion kann regelmäßig in einer for(open_trades)-Schleife aufgerufen werden, um den Status zwischen Broker und Strategie zu synchronisieren. Der GET_POSITION-Befehl muss von der Broker-API unterstützt werden, und es dürfen keine anderen Trades mit demselben Kontrakttyp, Strike, Verfall und Basiswert offen sein.

contractRoll (TRADE*, int Days, var Strike, function TMF): TRADE*

Verlängert einen geschlossenen Options- oder Futures-Kontrakt, indem ein Duplikat mit denselben Parametern (Typ, Volumen, Stop-Loss, Profitabstand) eröffnet wird, jedoch mit der angegebenen Anzahl Days Restlaufzeit, dem angegebenen Strike (0 um den alten Strike beizubehalten) und einer optionalen TMF. Gibt einen Zeiger auf den neuen Trade zurück oder 0, falls der Kontrakt nicht verlängert werden konnte. Quellcode in contract.c.

contractSellUnderlying(): int

Prüft im [Trade] Modus, ob eine Position des Basiswerts des aktuellen Assets offen ist, und verkauft diese gegebenenfalls zum Marktpreis. Gibt die Anzahl der Lots oder 0 zurück, falls keine Basiswertposition vorhanden war. Quellcode in contract.c.

contractExercise (TRADE*)

Übt einen Optionskontrakt aus. Im Backtest wird die Option zum inneren Wert geschlossen (siehe Bemerkungen). Im Live-Trading wird dem Broker ein Exercise-Auftrag geschickt, der normalerweise nicht sofort ausgeführt, sondern "pending" ist. Verwende contractCheck(), um den Trade zu schließen und den Basiswert zu verkaufen, sobald der Auftrag ausgeführt wurde. Rufe diese Funktion nicht bei europäischen Optionen vor Verfall auf oder bei Optionen, die nicht im Geld sind.
 

contractVal (CONTRACT*, var Price, var HistVol, var Dividend, var RiskFree, var* Delta, var* Gamma, var* Vega, var* Theta, var* Rho): var

Gibt den theoretischen Wert sowie optional die "Greeks" des angegebenen Optionskontrakts beim übergebenen nicht angepassten Price des Basiswertes zurück. Type, fStrike und Expiry des Kontrakts müssen gesetzt sein; andere Parameter sind irrelevant. Expiry kann entweder ein Verfallsdatum im Format YYYYMMDD sein oder alternativ die Anzahl an Kalendertagen bis zum Verfall. HistVol ist die jährliche Volatilität der logarithmierten Renditen, z.B. mithilfe der Volatility oder VolatilityOV (meistens über 20 Tage). Dividend ist die kontinuierliche jährliche Dividendenrendite des Basiswerts als Wert zwischen 0..1. RiskFree ist der jährliche risikofreie Zins als Bruchteil (0..1), z.B. yield()/100.
  Delta ist die Auswirkung einer Änderung des Basiswertpreises auf den Optionswert im Bereich 0..1 für Calls und 0..-1 für Puts. Gamma ist die Auswirkung auf Delta. Vega ist die Auswirkung einer Änderung der Basiswert-Volatilität, Theta ist die Auswirkung einer Änderung der Restlaufzeit und Rho ist die Auswirkung einer Änderung des risikofreien Zinssatzes.
  Diese Funktion nutzt R und das RQuantLib-Paket; beides muss installiert sein (siehe Bemerkungen unten). Quellcode in contract.c.

contractVol (CONTRACT*, var Price, var HistVol, var Value, var Dividend, var RiskFree): var

Ermittelt die implizite Volatilität (IV) des übergebenen Optionskontrakts zum Wert Value. Die Parameter entsprechen denen von contractVal. Die Funktion nutzt R und das RQuantLib-Paket; beide müssen auf dem Handels-PC installiert sein (siehe Bemerkungen unten). Quellcode in contract.c. Die implizite Volatilität ist eine Schätzung der zukünftigen Volatilität des Basiswerts auf Grundlage aktueller Optionsparameter. Hat der Kontrakt keinen Wert oder liegt sein Strikepreis zu weit bzw. auf der "falschen Seite" vom Basiswertpreis, gibt die Funktion 0 zurück. 

contractDelta (int Type, int Days, var Price, var HistVol, var RiskFree, var Strike): var

Gibt das theoretische Delta eines Kontrakts des Typs Type zurück, mit der angegebenen Restlaufzeit in Days, dem nicht angepassten Basiswertpreis Price, der Volatilität HistVol, dem risikofreien Zinssatz RiskFree und dem Strike. Verwendet die Formel Delta = cdf((ln(Price/Strike) + (r + (sigma^2)/2) * T) /(sigma * sqrt(T))). Quellcode in contract.c. Delta ist die erste Ableitung des Optionswertes bezüglich des Basiswertpreises und kann als Näherung für die Wahrscheinlichkeit angesehen werden, im Geld zu enden. Beachte, dass einige Plattformen und Broker individuelle Methoden zur Berechnung von HistVol verwenden, was zu abweichenden Delta-Werten für dieselben Kontrakte führen kann.

contractStrike (int Type, int Days, var Price, var HistVol, var RiskFree, var Delta): var

Gibt den theoretischen Strikepreis eines Kontrakts des Typs Type zurück, mit der angegebenen Restlaufzeit Days, dem nicht angepassten Basiswertpreis Price, der Volatilität HistVol, dem risikofreien Zinssatz RiskFree und dem Delta. Verwendet die Formel Strike = Price * exp(-qnorm(Delta) * sigma * sqrt(T) + (r + (sigma^2)/2) * T). Wenn für einen Put ein positives Delta eingegeben wird, wird es zum entsprechenden negativen Delta umgewandelt, sodass derselbe Delta-Wert sowohl für Puts als auch Calls genutzt werden kann. Quellcode in contract.c.

contractIntrinsic (CONTRACT*, var Price): var

contractIntrinsic (TRADE*, var Price): var

Gibt den inneren Wert des Optionskontrakts pro Basiswert-Einheit beim übergebenen Price des Basiswertes zurück. Der innere Wert einer Call-Option ist die Differenz zwischen Basiswertpreis und Strike; bei Puts die Differenz zwischen Strike und Basiswertpreis. Ist das Ergebnis positiv, ist die Option "im Geld", sonst liegt sie "aus dem Geld". Type und fStrike müssen im Kontrakt oder Trade gesetzt sein; andere Parameter sind unwichtig. Quellcode in contract.c.

contractProfit (CONTRACT*, var Price, var Premium): var

Gibt den Gewinn pro Basiswert-Einheit für einen Kontrakt zurück, der zum übergebenen Premium verkauft oder gekauft wurde und beim übergebenen Basiswertpreis Price verfällt. Premium ist positiv für verkaufte, negativ für gekaufte Kontrakte. Type und fStrike müssen im Kontrakt gesetzt sein; andere Parameter sind unwichtig. Handelskosten sind nicht eingeschlossen. Die Berechnung des Gewinns/Verlusts ist in den Bemerkungen unten beschrieben. Quellcode in contract.c.

contractMargin (CONTRACT*, int AssetType): var

Berechnet die Margin-Kosten des angegebenen unbedeckten (non-covered) Short-Put/Call-Kontrakts für den angegebenen AssetType (die Margin eines Long-Kontrakts ist einfach dessen Ask-Preis). Verwendet die Margin-Formel auf der IB-Seite US Options Margin Requirements. Quellcode in contract.c.

contractLetter (int AssetMonth): string

Gibt den Buchstaben für den angegebenen Verfallsmonat zurück (F Jan, G Feb, H Mär, J Apr, K Mai, M Jun, N Jul, Q Aug, U Sep, V Okt, X Nov, Z Dez). Quellcode in contract.c.
  

contractPrint()

Exportiert die aktuelle Kontraktkette in eine Data\*.csv-Datei zu Diagnosezwecken.

contractPrint(CONTRACT*)

Gibt die Parameter des übergebenen Kontrakts zu Diagnosezwecken in die Logdatei aus, in der Reihenfolge Datum, Typ, Ablauf, Strike, Basiswert, Ask, Bid, fVal, fVol. 

plotContract(int N, CONTRACT*, var HistVol, var Min, var Max, int Days, int Modus)

Zeichnet das Payoff-Diagramm von N Kontrakten (negativ für Verkauf) bei Volatilität HistVol, im Bereich von Min bis Max des Basiswertpreises. Modus 0 initialisiert den Plot und zeichnet eine Nulllinie, Modus 1 zeichnet das Diagramm zum Verfall, Modus 2 zum angegebenen Zeitpunkt Days innerhalb der Laufzeit (RQuantLib erforderlich), und Modus 3 zeichnet das Delta. Typ, Strike, Ask, Bid und Ablauf in Tagen müssen im CONTRACT-Struct gesetzt sein. Quellcode in contract.c; ein Beispiel in PayOff.c.

 

yield(): var

Hilfsfunktion, gibt die aktuelle Verzinsung von 3-monatigen US-Treasury-Bills in Prozent zurück. Kann als Stellvertreter für den risikofreien Zins bei der Optionsbewertung genutzt werden (Teile den Wert durch 100 für contractVal oder contractVol). Funktioniert im Backtest ebenso wie im Live-Handel. Nutzt die dataFromQuandl-Funktion. Zorro S wird für den Zugriff auf Quandl-Daten benötigt; trage deinen Quandl-Key in das Feld QuandlKey in Zorro.ini ein. Quellcode in contract.c.

yieldCSV(): var

Wie oben, aber der aktuelle Zinssatz wird aus einer bereits heruntergeladenen Treasury-Historie in History\FRED-DTB3.csv gelesen.

initRQL(): int

Hilfsfunktion zum Initialisieren von RQuantLib. Rufe diese Funktion im INITRUN auf, wenn contractVal oder contractVol verwendet werden.

 

Parameter:

Name Der Name des Basiswerts, z.B. "ES" oder "SPY", oder das Symbol (wenn es vom Namen abweicht) im Live-Trading, oder 0 für den Namen oder das Symbol des aktuellen Assets. Bei Kontraktketten im Backtestmodus verwende den Namen der aktuellen .t8-Datei, um monatliche oder tägliche Dateien zu laden.
Handle Eine Zahl von 1...800, die einen zuvor geladenen Datensatz referenziert, der eine CONTRACT-Liste mit historischen Optionsdaten enthält; oder 0, um Inhalte automatisch aus einer historischen Datei oder von der Broker-API zu laden.
Mode PUT|+CALL für Optionen, FUTURE für Futures, PUT+CALL+FUTURE für FOPs (Options on Futures).
Type Der exakte Kontrakttyp, eine Kombination aus PUT, CALL, FUTURE, EUROPEAN, BINARY (z.B. PUT+EUROPEAN) plus folgende optionale Flags:
+ONLYW3 - nur Kontrakte, die am 3. Freitag verfallen (16.-21. des Monats).
+ONLYMATCH - nur Kontrakte, die exakt dem Verfallsdatum entsprechen.
AssetType 1 für Währungen, 2 für Indizes, 3 für Aktien und ETFs. Die Margin für Futures muss individuell berechnet werden.
Days Die Mindestanzahl an Kalendertagen bis zum Verfall. Das nächste verfügbare Verfallsdatum wird gewählt.
Expiry Das Verfallsdatum im Format YYYYMMDD.
Strike Options-Strike; 0 für Futures.
Delta Erste Ableitung des Optionswertes in Bezug auf den Basiswertpreis. Bestimmt die Auswirkung einer Preisänderung des Basiswertes auf den Optionswert. Kann als Annäherung für die Wahrscheinlichkeit dienen, im Geld zu enden. 0..1 bei Calls und 0..-1 bei Puts.
HistVol Die historische annualisierte Volatilität des Basiswerts (z.B. 0.2 für 20%), meist berechnet mit den Volatility- oder VolatilityOV-Indikatoren über 20 Tage. Für die Greeks-Berechnung wird oft implizite Volatilität statt historischer Volatilität verwendet.
Dividend Die jährliche Dividendenrendite des Basiswerts als Bruchteil (z.B. 0.02 für 2%).
RiskFree Der risikofreie Zinssatz als Bruchteil (z.B. yield()/100).
Value Der Wert der Option zur Bestimmung der impliziten Volatilität.
TRADE* Zeiger auf einen Options- oder Future-Trade. Verwende ThisTrade als Zeiger in einer TMF oder Handelsschleife.

Bemerkungen:

  • contract.c muss eingebunden werden für alle Funktionen, die contract aufrufen. Der Basiswert muss ausgewählt sein und eine Kontraktkette muss geladen sein, bevor eine contract-Funktion aufgerufen wird.
  • Die Funktionen contractVal und contractVol benötigen zusätzlich R mit den Paketen Rcpp und RQuantLib, die über das Cran-Repository installiert werden können (entweder über install.packages oder RStudio-Menüs). Teste die Installation, indem du eine Library-Funktion wie oben gezeigt in der R-Konsole aufrufst. Starte RQuantLib im INITRUN mit initRQL. Beachte, dass die aktuelle RQuantLib-Version oft abstürzt, wenn unrealistische Parameter (z.B. negative Volatilität) übergeben werden. Nach solch einem Absturz geben alle RQuantLib-Funktionen 0 zurück.
  • Kontraktketten aus historischen Daten enthalten normalerweise Preise, Basiswert und optionale Daten wie Delta. Ketten, die vom Broker geladen werden, enthalten oft nur Strike und Ablaufdatum. Da das Laden von Optionsketten lange dauern kann (bis zu ~15 Minuten bei manchen Brokern), und sich Ablaufdaten und Strikes intraday nicht ändern, empfiehlt es sich, im Live-Trading contractUpdate nur einmal pro Tag aufzurufen, idealerweise außerhalb der Handelszeiten. Die Preise können danach mit contractPrice aktualisiert werden; Preise offener Trades werden automatisch aktualisiert. Im Test- und Trainingsmodus sollte contractUpdate bei jedem Bar aufgerufen werden, um die Preise zu aktualisieren.
  • Manche Broker liefern abgelaufene Kontrakte in ihrer Kette zurück. Prüfe daher immer das Verfallsdatum, wenn du einen Kontrakt auswählst.
  • Hochfrequente Optionsdaten können in monatliche oder tägliche .t8-Dateien aufgeteilt und pro Skript geladen werden. Diese Daten speist man dann in die contractUpdate-Funktion ein (siehe Beispiel).
  • Entry, Stop und TakeProfit funktionieren auch für Options- und Future-Trades. Sie müssen jedoch als absoluter Preis des Kontrakts (Ask) statt als Abstand angegeben werden. Wird eine Ausstiegsgrenze erreicht, wird der Kontrakt zum Marktpreis verkauft. Natürlich ist die Sinnhaftigkeit von Stop- oder Profitgrenzen bei Optionswerten umstritten.
  • Beim Öffnen eines Trades achte darauf, dass ein Kontrakt ausgewählt ist. Andernfalls würdest du versehentlich eine Position im Basiswert eröffnen. Prüfe mit contractPrice(), ob ein gültiger Ask- oder Bid-Preis (je nach Position) verfügbar ist, für Einzelkontrakte oder alle Kontrakte in einem Combo. Setze Multiplier korrekt, da sonst das Backtestergebnis falsch wäre. Einige Broker erfordern auch die Exchange. Den richtigen Multiplikator eines Options- oder Futurekontrakts findest du meist auf der Webseite des Brokers oder der Börse. Für Aktienoptionen beträgt der Multiplikator typischerweise 100.
  • Die durch assetHistory heruntergeladenen Basiswertpreise sind normalerweise split- und dividendenbereinigt und passen daher nicht zum Strike. Du kannst jedoch den UNADJUSTED-Flag verwenden, um unbereinigte Preise zu laden. Oft werden aber in einem Optionshandelssystem beide Preisarten benötigt: Unbereinigte Preise für Greeks oder Strike-Bestimmung und bereinigte Preise für historische Volatilität und Indikatoren. Üblich ist, im .t6-Verlauf bereinigte Kurse zu haben und für unbereinigte Kurse die Funktion contractUnderlying() zu verwenden.
  • Wird eine Option geschlossen - durch exit-Befehl oder Erreichen einer Stop-/Profit-Grenze - so wird sie automatisch zum aktuellen Ask-/Bid-Preis verkauft oder "gedeckt". Falls kein Marktpreis verfügbar ist, bleibt die Option offen, bis der nächste Exit-Befehl kommt oder sie verfällt/ausgeübt wird. Optionen und Futures können nur gehandelt werden, wenn der Markt geöffnet ist. Sende keine enter, exit oder exercise-Befehle außerhalb der Handelszeiten.
  • Wenn eine Option verfällt oder ausgeübt wird, kann eine Position im Basiswert entstehen. Im Live-Trading kann contractCheck prüfen, ob eine solche Basisposition existiert, und sie ggf. automatisch verkaufen. Im Backtest werden solche durch abgelaufene oder ausgeübte Optionen entstandenen Basiswertpositionen sofort zum Marktpreis verkauft und Gewinn/Verlust wird auf das Konto gebucht.
  • Zur Gewinn-/Verlustberechnung einer Option wird folgender Algorithmus verwendet:
    - Eine Call-Option ist "im Geld", wenn der Strike unterhalb des Bid-Preises liegt (Ask - Spread); eine Put-Option ist "im Geld", wenn der Strike oberhalb des Ask-Preises liegt.
    - Eine Long-Call- oder Short-Put-Position im Geld kauft den Basiswert zum Strike-Preis und verkauft ihn zum Bid-Preis. Die Differenz wird dem Konto gutgeschrieben bzw. belastet.
    - Eine Long-Put- oder Short-Call-Position im Geld verkauft den Basiswert zum Strike-Preis und kauft ihn zum Ask-Preis zurück. Die Differenz wird dem Konto gutgeschrieben bzw. belastet.
    - Für eine Long-Position wird die Prämie vom Konto subtrahiert, für eine Short-Position wird die Prämie gutgeschrieben.
  • Ein Beispiel zum Ermitteln der Parameter einer Rohstoff-FOP: Gehe auf https://www.cmegroup.com/trading und gib z.B. "Natural Gas" in das Suchfeld ein. Es erscheint eine Symbol-Liste (ansonsten musst du eine andere Börse checken). Wähle das Symbol mit dem höchsten Handelsvolumen, im Beispiel "NG". Klicke auf den Link unter Product Name. Dann wähle Contract Specs. Der Multiplikator (10.000 für NG) ist Contract Unit, die Pip-Größe ist Minimum Price Fluctuation ($0.001). Die Pip-Kosten betragen $0.001 in deiner Kontowährung. Unter Quotes sieht man den aktuellen Preis pro Basiswert-Einheit ($3.146). Prüfe, ob er in Cents oder Dollars angegeben ist (s.u.). Unter Margins sieht man, dass das nächstliegende November-2018-Kontrakt $1950 als Margin benötigt. Das sind $0.195 pro Basiswert-Einheit. Schau nun im Broker-Portal das Symbol und das Marginsystem an. Damit hast du alles, um den Basiswert in deine Assetliste einzutragen, z.B. NG,3.146,0.001,0,0,0.001,0.001,0.195,0,1,0.002,NG (auf einem USD-Konto).
  • Futures und FOPs haben ihre Preise manchmal in Cents, manchmal in Dollars, teils gemischt. Beim Handel mit FOPs solltest du historische Daten und Brokerangaben genau prüfen, um herauszufinden, welche Preise (Ask/Bid, Strike, Basiswert) in Cents und welche in Dollars angegeben sind. Dies kann sich je nach Future und Broker unterscheiden. Setze die Centage-Variable entsprechend, damit in deiner Strategie, den Charts und Berichten durchgehend Dollarpreise verwendet werden.
  • Das Klassen- oder Root-Symbol eines Kontrakts kann im Live-Trading aus dem ersten Element eines CONTRACT-Structs ausgelesen werden: string RootSymbol = (string)MyContract;. Beachte, dass dies nur im Live-Modus funktioniert, da im Backtest das erste CONTRACT-Element die Zeit ist.
  • Viele Broker-APIs, z.B. IB, verwalten keine Trades, sondern nur Positionen. Sie unterscheiden nicht zwischen einer Basiswertposition, die durch einen normalen Trade geöffnet wurde, und einer Position, die durch Ausübung einer Option entstanden ist. Dies muss im Skript berücksichtigt werden. Das gleichzeitige Long- und Shorthandeln desselben Kontrakts mit identischem Strike und Ablauf wird von Zorro als zwei verschiedene Trades geführt, aber vom Broker oft als zwei Positionen, die sich gegenseitig aufheben.
  • Einige Broker-APIs, z.B. IB, benötigen nach dem Download einer Optionskette eine gewisse "Erholungszeit", bevor die nächste Kette geladen werden kann. Lasse daher einige Sekunden (wait()) zwischen den Aufrufen von contractUpdate, wenn du Ketten mehrerer Assets nacheinander lädst.
  • Verwende den exit-Befehl, um einen Kontrakt durch Verkaufen oder Rückkauf zu schließen. Bei NFA-Konten prüfen Funktionen wie contractPosition oder contractCheck nur die Nettoposition. Sind also mehrere Long- und Shortpositionen desselben Kontrakts offen, liefern sie u.U. fehlerhafte Werte. Aus gleichem Grund können mehrere Skripte nicht dieselben Kontrakte auf demselben NFA-Konto handeln.
  • Slippage wird für Optionen nicht simuliert. Kommission und Margin werden standardmäßig aus den Kommissions- und Marginangaben des Basiswertes in der Assetliste abgeleitet und mit Multiplier multipliziert. Kommission wird um 50% reduziert, wenn eine Option wertlos verfällt. Da viele Broker unterschiedliche und komplexe Margin-Berechnungsmethoden für Optionen nutzen, ist die Standardberechnung nur eine grobe Annäherung. Für bessere Genauigkeit nutze contractMargin oder comboMargin oder berechne Commission und MarginCost explizit im Skript, bevor du den Trade eingehst. Beispielsweise bei vertikalen Spreads bestimmt sich die Margin oft aus der Differenz der Strikes, daher setze z.B. MarginCost = 0.5 * (Strike1 - Strike2), bevor du die zwei Positionen eingehst. Die Margin bedeckter Optionen ist meist 0. IBs Margin-Anforderungen findest du unter https://www.interactivebrokers.com/en/index.php?f=24176.
  • Bei der Optimierung von Optionsstrategien ist die Standard-objective-Funktion nicht optimal. Besser ist, den Gesamtgewinn durch die benötigte Margin zu teilen. Beispiel:
    var objective()
    {
      if(!NumWinTotal && !NumLossTotal) return 0;
      return (WinTotal-LossTotal)/MarginMax;
    }
    
  • Phantom-Trades und virtuelles Hedging werden bei Kontrakten nicht verwendet. Optionen können unabhängig von der Hedge-Einstellung immer gehedged werden.
  • Einige historische Optionen vor 2014 verfielen an einem Samstag; später war der Verfall am Freitag. Optionen mit Samstagsverfall werden so behandelt, als verfielen sie am Freitag. Die Verfallsstunde kann über ExpiryTime gesetzt werden.
  • Die Struktur CONTRACT ist in trading.h definiert. Für Backtests müssen die folgenden Elemente im Datensatz gefüllt sein; bei Futures: time, fAsk, fBid, Expiry, Type; bei Optionen: time, fAsk, fBid, fStrike, Expiry, Type. Alle weiteren Elemente in CONTRACT sind optional und nur für Skripte gedacht.
  • contract(Contracts) wählt den ersten Kontrakt in der Kette aus.
  • Zur Berechnung des Optionswerts werden amerikanische Optionen per Crank-Nicolson-Verfahren approximiert, während europäische Optionen mit der (wesentlich schnelleren) Black-Scholes-Formel berechnet werden. Bei kurzlaufenden Optionen sind die Resultate beider Methoden meist ähnlich, daher kann man in solchen Fällen auch bei amerikanischen Optionen das EUROPEAN-Flag verwenden, um die Berechnungszeit zu reduzieren.
  • Die Funktion contractVol ist dafür bekannt, die R-Session zu beenden, wenn sie mit unplausiblen Parametern aufgerufen wird, z.B. wenn ein extrem kleiner Optionswert für einen hohen Strike/Spot-Abstand und kurze Laufzeit übergeben wird. Dies kann man mit Rrun abfangen (if(!Rrun()) quit("R terminated!");). Terminiert die R-Session so im Backtest, muss Zorro neu gestartet werden.
  • Um einen Kontrakt mit dem niedrigsten Strike zu finden, der bestimmte Kriterien erfüllt, beginnt man mit dem aktuellen Basiswertpreis als Strike, ruft contract(...) in einer Schleife auf und ändert den Strike in Schritten, bis die Bedingung erfüllt ist. Für Calls steigert man den Strike, für Puts verringert man ihn.
  • Für die Umwandlung von Daten ins Format YYYYMMDD oder um den 3. Freitag im Monat zu finden, verwende die Funktionen dmy, ymd und nthDay.
  • Es liegen mehrere Optionsskripte bei. Das Skript TradeOptions kann z.B. das Öffnen und Schließen von SPY-Optionen über die Broker-API testen. Es läuft nur während NY-Handelszeiten und benötigt etwa 30 Sekunden, um beim Start die Optionskette zu laden. Mit dem Skript Payoff lassen sich Payoff- und Delta-Diagramme von Optionskombinationen interaktiv anzeigen. Das OptionsCalculator-Skript berechnet Preise und Delta für Calls und Puts, wobei Basiswert, Strike und Laufzeit per Slider eingestellt werden können. Du kannst diese Skripte frei kombinieren, um dein eigenes Options-Tool zu erstellen.

Beispiele:

// Verkaufe Call- und Put-Optionen in einer Standardabweichung Entfernung
// Kaufe sie 2 Tage vor Verfall zurück
#include <contract.c>

void run() 
{
  BarPeriod = 1440;
  BarZone = EST;
  BarOffset = 15*60; // Handel um 15:00 Eastern
  LookBack = 20;
  if(Init) {
    assetList("AssetsIB");
    assetHistory("SPY",FROM_AV|UNADJUSTED);
    brokerCommand(SET_CLASS,"SPYW");
  }
  asset("SPY");
  Multiplier = 100;
 
  if(!NumOpenTotal && !is(LOOKBACK)) {
    contractUpdate(Asset,0,PUT|CALL);
    vars Close = seriesC();  
    int DTE = 6*7; // Suche Kontrakte mit 6 Wochen Restlaufzeit
    var Strangle = StdDev(Close,20);
    CONTRACT* Call = contract(CALL,DTE,Close[0] + Strangle);
    CONTRACT* Put = contract(PUT,DTE,Close[0] - Strangle);
    if(Call && Put) { // Öffne einzelne Positionen, kein Combo
      contract(Call); enterShort();
      contract(Put); enterShort();
    }
  }

// Prüfe Verfall und kaufe zurück, wenn im Geld
  for(open_trades) 
  {
    if(contractDays(ThisTrade) <= 2
      && contractIntrinsic(ThisTrade,Close[0]) > 0)
         exitTrade(ThisTrade);
  }
}
// Lade hochauflösende Kontraktketten aus Tagesdateien wie "SPY_20210505.t8"
if(day(0) != day(1)) { // Neuer Tag?
  if(Live) // Lade eine neue Kontraktkette ohne Preise
    contractUpdate(0,1,CALL|PUT);
  else // Lade eine neue .t8 mit Preisen
    dataLoad(1,strf("History\\%s_%04d%02d%02d.t8",Asset,year(0),month(0),day(0)),9);
}
if(!Live) // Im Backtest Preise bei jedem Bar updaten
  contractUpdate(0,1,CALL|PUT);
// Beispielskript zum Konvertieren von EOD-Optionsdaten in .t8:
// Format: underlying symbol, exchange, date MMDDYYYY, adj close, option symbol, expiry MMDDYYYY, strike, Call/Put, American/European, ask, bid, volume, open interest, close
// Beispiel: "TLT,NYSEArca,04/10/2015,129.62,TLT   150410C00112500,04/10/2015,112.5,C,A,17.3,16.2,0,0,129.62"

string Format = ",,%m/%d/%Y,,,i,f,s,s,f,f,f,f,f";

void main() 
{
// Erster Schritt: CSV-Datei parsen und in Datensatz einlesen
  int Records = dataParse(1,Format,FILENAME);
  printf("\n%d Datensätze geparst",Records);
// Zweiter Schritt: Rohe Daten ins CONTRACT-Format umwandeln
  for(i=0; i<Records; i++) 
  {
    CONTRACT* C = dataAppendRow(2,9);
    C->time = dataVar(1,i,0);
    string PC = dataStr(1,i,3);
    string EA = dataStr(1,i,4);
    C->Type = ifelse(*PC == 'P',PUT,CALL) + ifelse(*EA == 'E',EUROPEAN,0);
    int Expiry = dataInt(1,i,1); 
    C->Expiry = 10000*(Expiry%10000) + Expiry/10000; // MMDDYYYY -> YYYYMMDD
    C->fStrike = dataVar(1,i,2);
    C->fAsk = dataVar(1,i,5);
    C->fBid = dataVar(1,i,6);
    C->fVol = dataVar(1,i,7);
    C->fVal = dataVar(1,i,8); // Open Interest
    C->fUnl = dataVar(1,i,9);
    if(!progress(100*i/Records,0)) break; // Zeige Fortschrittsbalken
  }
  dataSort(2);
  dataSave(2,"History\\MyOptions.t8");
}

Siehe auch:

enterLong/Short, exitLong/Short, Quandl bridge, Datum-Funktionen, Kontrakt-Variablen, contractCPD, combo, workshop 8

 

► neueste Version online