Overall Statistics |
Total Trades 1 Average Win 0% Average Loss 0% Compounding Annual Return -6.151% Drawdown 5.900% Expectancy 0 Net Profit -4.852% Sharpe Ratio -0.974 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.141 Beta 5.796 Annual Standard Deviation 0.051 Annual Variance 0.003 Information Ratio -1.28 Tracking Error 0.051 Treynor Ratio -0.009 Total Fees $0.00 |
/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Globalization; using QuantConnect.Data; using QuantConnect.Data.Market; namespace QuantConnect.Algorithm.CSharp { public class InterestAlgorithm : QCAlgorithm { QuantConnect.Symbol soybn; private Dictionary<string,Interest> interestList = new Dictionary<string,Interest>(); /// <summary> /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. /// </summary> public override void Initialize() { SetStartDate(2018, 6, 3); SetEndDate(2019, 3, 13); //Set the cash for the strategy: SetCash("EUR",100000); //Define the symbol and "type" of our generic data: AddData<Interest>("SOYBN", Resolution.Daily); AddData<Interest>("USD", Resolution.Daily); var eurusd = QuantConnect.Symbol.Create("EURUSD", SecurityType.Forex, Market.Oanda); AddSecurity(SecurityType.Forex,eurusd, Resolution.Daily); soybn = QuantConnect.Symbol.Create("SOYBNUSD", SecurityType.Cfd, Market.Oanda); AddSecurity(SecurityType.Cfd,soybn,Resolution.Daily); SetWarmUp(TimeSpan.FromDays(10)); } public override void OnData(Slice data) { if(IsWarmingUp) { return; } if (!Portfolio.Invested) { MarketOrder(soybn, 5000); Debug("Purchased Soy"); } } //For a long position: //Financing Charges on Base = units * ({BASE}Interest Rate %) * (Time in years) * ({BASE}/Primary Currency) //Financing Charges on Quote = (converted units) * ({QUOTE} Interest Rate %) * (Time in years) * ({QUOTE}/Primary Currency) //Total Financing = Financing Charges on Base - Financing Charges on Quote //For a short position: //Financing Charges on Quote = (converted units) * ({QUOTE} Interest Rate %) * (Time in years) * ({QUOTE}/Primary Currency) //Financing Charges on Base = units * ({BASE} Interest Rate %) * (Time in years) * ({BASE}/Primary Currency) //Total Interest = Financing Charges on Quote - Financing Charges on Base private void CalculateInterest() { foreach (var security in Portfolio.Securities.Values) { if(security.Invested) { var units = security.Holdings.AbsoluteQuantity; Interest quotesymbol; Interest basesymbol; interestList.TryGetValue(security.QuoteCurrency.Symbol, out quotesymbol); interestList.TryGetValue(security.Symbol.ID.Symbol.Replace(security.QuoteCurrency.Symbol, ""), out basesymbol); if (basesymbol == null || quotesymbol == null) { return; } if (security.Holdings.Quantity>0) { var baseInterest = basesymbol.Bid; //borrow var yearsecs = 365*24*60*60m; var timeyears = (decimal)security.Exchange.Hours.RegularMarketDuration.TotalSeconds / yearsecs; var tradePrice = security.Price; var accountCurrency = 1/Portfolio.Securities["EURUSD"].Price; //convert usd to eur var quoteInterest = quotesymbol.Ask; //lend var value = units * timeyears * (baseInterest / 100) * tradePrice * accountCurrency; var v2 = units * timeyears * (quoteInterest / 100) * tradePrice * accountCurrency; var result = value - v2; Debug(string.Format("{0} {1} {2} {3:N2}", basesymbol.Bid, quotesymbol.Ask, Time, result)); Portfolio.CashBook["EUR"].AddAmount(result); //security.Holdings.AddNewFee(result); Debug(string.Format("{0:N2}", Portfolio.CashBook["EUR"].Amount)); } else { var baseInterest = basesymbol.Ask; //lend var yearsecs = 365 * 24 * 60 * 60m; var timeyears = (decimal)security.Exchange.Hours.RegularMarketDuration.TotalSeconds / yearsecs; var tradePrice = security.Price; var accountCurrency = 1 / Portfolio.Securities["EURUSD"].Price; //convert usd to eur var quoteInterest = quotesymbol.Bid; //borrow var value = units * timeyears * (baseInterest / 100) * tradePrice * accountCurrency; var v2 = units * timeyears * (quoteInterest / 100) * tradePrice * accountCurrency; var result = v2 - value; Debug(string.Format("{0} {1} {2} {3:N2}", basesymbol.Ask, quotesymbol.Bid, Time, result)); Portfolio.CashBook["EUR"].AddAmount(result); //security.Holdings.AddNewFee(result); Debug(string.Format("{0:N2}", Portfolio.CashBook["EUR"].Amount)); } } } } /// <summary> /// OnData is the primary entry point for youm algorithm. New data is piped into your algorithm here /// via TradeBars objects. /// </summary> /// <param name="data">TradeBars IDictionary object</param> public void OnData(Interest data) { try { if(interestList.ContainsKey(data.Symbol.ID.Symbol)) { interestList.Remove(data.Symbol.ID.Symbol); } interestList.Add(data.Symbol.ID.Symbol, data); //Debug(string.Format("{0} {1} {2} {3} {4}", data.Symbol.ID.Symbol, data.Bid, data.Ask, data.DateTime, Time)); } catch (Exception err) { Debug("Error: " + err.Message); } } /// <summary> /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets). /// </summary> /// <remarks>Method is called 10 minutes before closing to allow user to close out position.</remarks> public override void OnEndOfDay() { CalculateInterest(); } } /// <summary> /// Interest Custom Data Class /// </summary> public class Interest : BaseData { /// <summary> /// Bid Rate /// </summary> public decimal Bid; /// <summary> /// Ask Rate /// </summary> public decimal Ask; /// <summary> /// Instrument /// </summary> public string Instrument; /// <summary> /// DateTime /// </summary> public DateTime DateTime; /// <summary> /// Default initializer for Interest. /// </summary> public Interest() { } /// <summary> /// Return the URL string source of the file. This will be converted to a stream /// </summary> public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode) { //"http://127.0.0.1:8080/interest.csv" return new SubscriptionDataSource("http://www.mocky.io/v2/5c8abc1b2e0000b732d64dc9", SubscriptionTransportMedium.RemoteFile); } /// <summary> /// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object /// each time it is called. /// </summary> public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode) { //New Interest object var interest = new Interest(); try { //Example File Format: //CURRENCY,INSTRUMENT,BID,ASK,TEXTDATE,DATE,HOUR //Australia 200,AU200,4.1300,6.6800,Wed Dec 19 19:09:25 2018,20181219,19:09:25 //Australia 200,AU200,1.0500,2.0000,Wed Dec 19 07:04:29 2018,20181207,07:04:29 var data = line.Split(';'); interest.Symbol = data[1]; interest.Bid = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture); interest.Ask = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture); interest.DateTime = System.DateTime.ParseExact(string.Format("{0} {1} GMT", data[5], data[6]), "yyyyMMdd HH:mm:ss Z", CultureInfo.InvariantCulture); interest.Time = System.DateTime.ParseExact(string.Format("{0} {1} GMT", data[5], data[6]), "yyyyMMdd HH:mm:ss Z", CultureInfo.InvariantCulture); //interest.Time = System.DateTime.ParseExact(string.Format("{0} GMT", data[5]), "yyyyMMdd Z", CultureInfo.InvariantCulture); interest.Value = 1m; } catch { } return interest; } } }