| Overall Statistics |
|
Total Trades 75 Average Win 0.15% Average Loss -0.01% Compounding Annual Return 83.363% Drawdown 5.500% Expectancy 8.547 Net Profit 22.067% Sharpe Ratio 2.569 Loss Rate 19% Win Rate 81% Profit-Loss Ratio 10.79 Alpha 0.301 Beta 1.825 Annual Standard Deviation 0.2 Annual Variance 0.04 Information Ratio 2.489 Tracking Error 0.159 Treynor Ratio 0.281 Total Fees $100.69 |
/*
* 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 QuantConnect.Data;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Data.Custom;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Data.Consolidators;
namespace QuantConnect.Algorithm.CSharp
{
public class StockRankAlgorithm : QCAlgorithm
{
// algorythm settings
const Resolution _algo_resolution = Resolution.Daily;
public const decimal _startingcash = 100000m;
public const decimal _positionweight = 0.10m;
private int _lastmonth = 0;
// public DateTime _startdate = new DateTime(2007, 11, 23);
// public DateTime _enddate = new DateTime(2014, 11, 23);
public DateTime _startdate = DateTime.Now.Date.AddDays(-120);
public DateTime _enddate = DateTime.Now.Date.AddDays(-1);
// sort the data by daily dollar volume and take the top 'NumberOfSymbolsCoarse'
public IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse)
{
var hasmorningstar = from x in coarse
//where (x.HasFundamentalData && x.DollarVolume > 200000000m && x.DollarVolume > 500000000m)
where (x.HasFundamentalData && x.DollarVolume > 20000000m && x.DollarVolume > 70000000m)
orderby x.DollarVolume ascending
select x.Symbol;
// we need to return only the symbol objects
return hasmorningstar.Take(100);
}
// calculate the f-score
private int FScore(
decimal netincome,
decimal operating_cashflow,
decimal roa_current, decimal roa_past,
decimal issued_current, decimal issued_past,
decimal grossm_current, decimal grossm_past,
decimal longterm_current, decimal longterm_past,
decimal curratio_current, decimal curratio_past,
decimal assetturn_current, decimal assetturn_past
)
{
int fscore = 0;
fscore += (roa_current > 0m ? 1 : 0 ); // return on assets is positive
fscore += ( operating_cashflow > 0m ? 1 : 0 ); // operating cashflow in current year is positive
fscore += ( roa_current >= roa_past ? 1 : 0 ); // roa has increased since last Time
fscore += ( operating_cashflow > roa_current ? 1 : 0 ); // cashflow from current operations are greater than roa
fscore += ( longterm_current <= longterm_past ? 1 : 0 ); // a decrease in the long term debt ratio
fscore += ( curratio_current >= curratio_past ? 1 : 0 ); // an increase in the current ratio
fscore += ( issued_current <= issued_past ? 1 : 0 ); // no new shares have been issued
fscore += ( grossm_current >= grossm_past ? 1 : 0 ); // an increase in gross margin
fscore += ( assetturn_current >= assetturn_past ? 1 : 0 ); // a higher asset turnover ratio
// Debug("<<<<<<");
//Debug("f-score :" +fscore);
// Debug("roa current : " + roa_current);
// Debug("operating cashflow : " + operating_cashflow);
// Debug("roa current : " + roa_current + " past : " + roa_past);
// Debug("operating cashflow : " + operating_cashflow );
// Debug("longterm_current : " + longterm_current + " past : " + longterm_past);
// Debug("curratio_current : " + curratio_current + " past : " + curratio_past);
// Debug("issued current : " + issued_current + " : past " + issued_past);
// Debug("grossm current : " + grossm_current + " : past " + grossm_past);
// Debug("assetturn_current : " + assetturn_current + " : " + assetturn_past);
return fscore;
}
// sort the data by P/E ratio and take the top 'NumberOfSymbolsFine'
public IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine)
{
// find piatroski score
var piatroskiscore = from x in fine
let fs = FScore(
x.FinancialStatements.IncomeStatement.NetIncome.TwelveMonths,
x.FinancialStatements.CashFlowStatement.CashFlowFromContinuingOperatingActivities.TwelveMonths,
x.OperationRatios.ROA.ThreeMonths, x.OperationRatios.ROA.OneYear,
x.FinancialStatements.BalanceSheet.ShareIssued.ThreeMonths, x.FinancialStatements.BalanceSheet.ShareIssued.TwelveMonths,
x.OperationRatios.GrossMargin.ThreeMonths, x.OperationRatios.GrossMargin.OneYear,
x.OperationRatios.LongTermDebtEquityRatio.ThreeMonths, x.OperationRatios.LongTermDebtEquityRatio.OneYear, // fix need last year
x.OperationRatios.CurrentRatio.ThreeMonths, x.OperationRatios.CurrentRatio.OneYear, // fix need last year
x.OperationRatios.AssetsTurnover.ThreeMonths, x.OperationRatios.AssetsTurnover.OneYear // fix need last year
)
where (fs >= 5)
orderby fs descending
select x;
// take the top entries from our sorted collection
var topFine = piatroskiscore.Take(10);
Debug("Found " + topFine.Count() + " possibilities");
// foreach (var s in topFine)
// {
// Debug(s.ToString());
// }
// we need to return only the symbol objects
return topFine.Select(x => x.Symbol);
}
// Initialize the data and resolution you require for your strategy:
public override void Initialize()
{
SetStartDate(_startdate);
SetEndDate(_enddate);
// don't do any margin stuff
SetBrokerageModel(Brokerages.BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash);
//Cash allocation
SetCash(_startingcash);
UniverseSettings.Resolution = _algo_resolution;
// this add universe method accepts two parameters:
// - coarse selection function: accepts an IEnumerable<CoarseFundamental> and returns an IEnumerable<Symbol>
// - fine selection function: accepts an IEnumerable<FineFundamental> and returns an IEnumerable<Symbol>
AddUniverse(CoarseSelectionFunction, FineSelectionFunction);
}
public override void OnData(Slice slice)
{
// only rebalance every month
if (slice.Time.Month != _lastmonth)
{
_lastmonth = slice.Time.Month;
// sell what we are no longer interested iinterested
foreach (var pos in Portfolio.Keys)
{
if (Portfolio[pos].HoldStock)
{
var check = from x in slice.Bars
where (x.Value.Symbol == pos)
select x.Value.Symbol;
if (check.Count() == 0)
SetHoldings(pos, 0m);
}
}
// buy highly ranked stocks
foreach ( var bar in slice.Bars)
SetHoldings(bar.Value.Symbol, _positionweight);
}
}
}
}