| 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;
}
}
}