| Overall Statistics |
|
Total Trades 134 Average Win 0.21% Average Loss -0.07% Compounding Annual Return 1319.775% Drawdown 0.900% Expectancy 1.370 Net Profit 6.793% Sharpe Ratio 10.879 Loss Rate 40% Win Rate 60% Profit-Loss Ratio 2.97 Alpha 1.629 Beta 0.403 Annual Standard Deviation 0.154 Annual Variance 0.024 Information Ratio 10.149 Tracking Error 0.154 Treynor Ratio 4.153 Total Fees $5.26 |
using System;
using System.Linq;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using System.Drawing;
namespace QuantConnect.Algorithm.CSharp
{
public class BasicTemplateAlgorithm : QCAlgorithm
{
private string _sym = QuantConnect.Symbol.Create("BTCUSD", SecurityType.Crypto, Market.GDAX);
private List<OrderTicket> _openLimitOrders = new List<OrderTicket>();
private RollingWindow<TradeBar> History = new RollingWindow<TradeBar>(5);
private decimal at_risk_amount = 2000;
private decimal target_exit_price = 0.0m;
private decimal target_cover_price = 0.0m;
private decimal buy_back_amount = 0.0m;
private RelativeStrengthIndex rsi_now;
private AbsolutePriceOscillator apo_now;
private AverageTrueRange atr_now;
private bool go_long = false;
private bool go_short = false;
private int frequency = 2;
private int entry_counter = 260/2;
private int exit_counter = 36000/2;
private bool in_trade_long = false;
private bool in_trade_short = false;
private bool stop_set = false;
private decimal target_stop_price = 0.0m;
private decimal current_price = 0.0m;
private decimal entry_point_long = 0.0m;
private decimal entry_point_short = 0.0m;
private decimal entry_point_amount = 0.0m;
private decimal previous_equity = 0.0m;
private decimal windfall_measure = 0.0m;
public override void Initialize()
{
Debug("Init");
SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash);
DateTime dt = new DateTime(2017, 11, 1, 12, 2, 7, 0);
SetStartDate(dt); //Set Start Date
DateTime dt1 = new DateTime(2017, 11, 9, 12, 4, 7, 0);
SetEndDate(dt1); //Set Start Date
//SetEndDate(DateTime.Now);
AddCrypto("BTCUSD", Resolution.Second, Market.GDAX);
SetCash(at_risk_amount);
Debug("Basic Setup completed");
//every second for order timeframe
var consolidator = new TradeBarConsolidator(frequency);
consolidator.DataConsolidated += OrderHandler;
SubscriptionManager.AddConsolidator("BTCUSD", consolidator);
Debug("Consolidator 1 added...");
//every five minutes for indicator timeframe
var consolidator2 = new TradeBarConsolidator(5*60);
consolidator2.DataConsolidated += DecisionHandler;
var consolidator3 = new TradeBarConsolidator(15*60);
//consolidator3.DataConsolidated += StopHandler;
rsi_now = RSI("BTCUSD", 14, MovingAverageType.Simple);
apo_now = APO("BTCUSD", 12, 26, MovingAverageType.Exponential);
atr_now = ATR("BTCUSD", 14, MovingAverageType.Simple);
RegisterIndicator("BTCUSD", rsi_now, consolidator2);
RegisterIndicator("BTCUSD", apo_now, consolidator2);
SubscriptionManager.AddConsolidator("BTCUSD", consolidator2);
Debug("Consolidator 2 added...");
//SubscriptionManager.AddConsolidator("BTCUSD", consolidator3);
//Debug("Consolidator 3 added...");
//set sold to true, to trigger first trade in buy direction
Chart plotter = new Chart("Plotter");
plotter.AddSeries(new Series("Price", SeriesType.Line, index:0));
//plotter.AddSeries(new Series("RSI", SeriesType.Line, index:0));
//plotter.AddSeries(new Series("APO", SeriesType.Line, index:0));
plotter.AddSeries(new Series("Buy", SeriesType.Scatter, string.Empty, Color.Green, ScatterMarkerSymbol.Triangle));
plotter.AddSeries(new Series("Sell", SeriesType.Scatter, string.Empty, Color.Red, ScatterMarkerSymbol.TriangleDown));
AddChart(plotter);
}
private void DecisionHandler(object sender, BaseData consolidated2)
{
//Debug("Price: " + consolidated2.Price);
Plot("Plotter", "Price", consolidated2.Price);
if(!rsi_now.IsReady) return;
if(!apo_now.IsReady) return;
if (rsi_now.Current.Value > 50
&& rsi_now.Current.Value < 70
&& apo_now.Current.Value > 0
&& !in_trade_long && !in_trade_short)
//isRisingRSI(rsi_now) )
{
Log("LONG Trigger. Price: " + consolidated2.Price);
go_long = true;
}
Debug("APO: " + apo_now.Current.Value);
//if(in_trade_long)https://www.quantconnect.com/terminal/#
// Debug("IN TRADE: Long");
//if(in_trade_short)
// Debug("IN TRADE: Short");
Debug("BTC Holdings in USD: $" + Convert.ToString(Portfolio.CashBook["BTC"].ValueInAccountCurrency));
Debug("BTC Holdings in BTC: B" + Convert.ToString(Portfolio.CashBook["BTC"].ValueInAccountCurrency / consolidated2.Price));
Debug("Equity in USD: $" + Convert.ToString(Portfolio.Cash));
}
private void OrderHandler(object sender, BaseData consolidated)
{
//Plot(_sym, "Price", consolidated.Price);
//Debug("Price: " + consolidated.Price);
if(go_long)
{
decimal amnt = Math.Round(Portfolio.Cash / consolidated.Price, 4);
ExecuteLimitOrder("BTCUSD", amnt, Math.Round((decimal)consolidated.Price,2), "buy");
entry_point_long = (decimal)consolidated.Price;
entry_point_amount = amnt;
}
if(in_trade_long)
{
if(previous_equity > 0){
var diff = Portfolio.Cash - previous_equity;
//Debug("Diff: " + diff);
//Debug("Pre: " + previous_equity);
windfall_measure = (diff / previous_equity) * 100;
//Debug(windfall_measure.ToString());
}
//Debug("Equity increase: " + windfall_measure);
current_price = consolidated.Price;
decimal amnt = entry_point_amount;
ExecuteLimitOrder("BTCUSD", amnt, target_exit_price, "sell");
}
}
/*
Will trigger limit order, adjust price to
*/
private decimal ExecuteLimitOrder(string symbol, decimal amnt, decimal price, string direction)
{
if(in_trade_long && windfall_measure > 0.5m){
Debug("WINDFALL ALERT - get out now!");
Transactions.CancelOpenOrders("BTCUSD");
Debug("AReset counters...Timeout");
go_long = false;
go_short = false;
in_trade_long= false;
in_trade_short= false;
entry_counter = 260/frequency;
Liquidate("BTCUSD");
return 0.0m;
}
if(entry_counter == 0){
Transactions.CancelOpenOrders("BTCUSD");
Debug("AReset counters...Timeout");
go_long = false;
go_short = false;
in_trade_long= false;
in_trade_short= false;
entry_counter = 260/frequency;
return 0.0m;
}
if(exit_counter == 0)
{
//Either drop what you have if we are positive and reset that way
//or... emergency stop.
if(in_trade_long && current_price > entry_point_long){
Debug("Liquidating...");
Liquidate("BTCUSD");
}
else{
Debug("Current Price: " + current_price);
Debug("Entry Point Long: " + entry_point_long);
Debug("Entry Point Short: " + entry_point_short);
Debug("LONG: " + in_trade_long);
Debug("SHORT: " + in_trade_short);
Quit(); //Option: Instruct algorithm to stop.
}
Transactions.CancelOpenOrders("BTCUSD");
Debug("BReset counters...Timeout");
go_long = false;
go_short = false;
in_trade_long= false;
in_trade_short= false;
exit_counter = 36000/frequency;
Debug("We are stuck - no exit was possible. Why???");
Debug("Could not exit in given time. Halting algorithm.");
return 0.0m;
}
//Debug("Order Handler");
List<Order> myOrders = Transactions.GetOpenOrders("BTCUSD");
if (myOrders.Count <= 0)
{
//Debug(Time.ToString() + " Submitting LimitOrder");
if(direction == "sell"){
Debug("Let's sell...");
LimitOrder("BTCUSD", -1*amnt, price + 0.01m);
Debug(Time.ToString() + " Amount: " + -1*amnt);
Debug(Time.ToString() + " Price: " + (price + 0.01m));
if(in_trade_long || in_trade_short)
exit_counter--;
else
entry_counter--;
Debug("EntryCounter: " + entry_counter);
Debug("ExitCounter: " + exit_counter);
}
else if (direction == "buy"){
if(go_long) Debug("Let's buy..."); else Debug("Let's cover");
LimitOrder("BTCUSD", amnt, price - 0.01m);
Debug(Time.ToString() + " Amount: " + amnt);
Debug(Time.ToString() + " Price: " + (price - 0.01m));
if(in_trade_long || in_trade_short)
exit_counter--;
else
entry_counter--;
Debug("EntryCounter: " + entry_counter);
Debug("ExitCounter: " + exit_counter);
}
}
else
{
if(in_trade_long || in_trade_short) exit_counter--; else entry_counter--;
if(exit_counter < (36000/frequency) && exit_counter % 10 == 0){
if(in_trade_long && current_price < target_stop_price ){
Debug("STOP TRIGGERED - Get out of LONG");
Transactions.CancelOpenOrders("BTCUSD");
LimitOrder("BTCUSD", -1*amnt, current_price + 0.01m);
}
}
}
return 0.0m;
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
var order = Transactions.GetOrderById(orderEvent.OrderId);
Debug(Time + ": " + order.Type + " - " + orderEvent);
if(orderEvent.Status == OrderStatus.Filled)
{
if(order.Direction.ToString() == "Buy")
Plot("Plotter", "Buy", orderEvent.FillPrice);
else
Plot("Plotter", "Sell", orderEvent.FillPrice);
Debug("Order got filled: " + orderEvent.OrderId);
Debug("EntryCounter: " + entry_counter);
Debug("ExitCounter: " + exit_counter);
if(go_long && entry_counter < (260/frequency)){
in_trade_long = true;
go_long = false;
target_exit_price = orderEvent.FillPrice + 10m;
target_stop_price = orderEvent.FillPrice - atr_now.Current.Value;
Debug("Exit Stop Price: " + target_stop_price);
Debug("Exit Target Price: " + target_exit_price);
entry_point_amount = orderEvent.FillQuantity;
previous_equity = Portfolio.Cash;
}
if(in_trade_long && exit_counter < (36000/frequency)){
in_trade_long = false;
go_long = false;
Debug("Closed LONG - NOT IN TRADE");
}
if(in_trade_short && exit_counter < (36000/frequency)){
in_trade_short = false;
go_short = false;
Debug("Covered SHORT - NOT IN TRADE");
}
Debug("Reset counters...2");
entry_counter = 260/frequency;
exit_counter = 36000/frequency;
}
}
}
}