Skip to content

Commit

Permalink
Improves Universe Selection for python
Browse files Browse the repository at this point in the history
In python algorithm using Universe Selection, the selector method should return a List<Symbol>. To make it more pythonic, we allow returning python list. The conversion is, then, performed in C# side.
  • Loading branch information
AlexCatarino committed Sep 26, 2017
1 parent 7d2a67c commit 3da8449
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 48 deletions.
18 changes: 2 additions & 16 deletions Algorithm.Python/CoarseFineFundamentalComboAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,29 +58,15 @@ def CoarseSelectionFunction(self, coarse):
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)

# return the symbol objects of the top entries from our sorted collection
top5 = sortedByDollarVolume[:self.__numberOfSymbols]

# we need to return only the symbol objects
list = List[Symbol](len(top5))
for x in top5:
list.Add(x.Symbol)

return list
return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]

# sort the data by P/E ratio and take the top 'NumberOfSymbolsFine'
def FineSelectionFunction(self, fine):
# sort descending by P/E ratio
sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.PERatio, reverse=True)

# take the top entries from our sorted collection
topFine = sortedByPeRatio[:self.__numberOfSymbolsFine]

list = List[Symbol](len(topFine))
for x in topFine:
list.Add(x.Symbol)

return list

return [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ]

def OnData(self, data):
# if we have no changes, do nothing
Expand Down
8 changes: 3 additions & 5 deletions Algorithm.Python/EmaCrossUniverseSelectionAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,11 @@ def CoarseSelectionFunction(self, coarse):
# Sorts the values of the dict: we want those with greater difference between the moving averages
values.sort(key=lambda x: x.scale, reverse=True)

# we need to return only the symbol objects
list = List[Symbol]()
for x in values[:self.coarse_count]:
self.Log('symbol: ' + str(x.symbol.Value) + ' scale: ' + str(x.scale))
list.Add(x.symbol)

return list

# we need to return only the symbol objects
return [ x.symbol for x in values[:self.coarse_count] ]

# this event fires whenever we have changes to our universe
def OnSecuritiesChanged(self, changes):
Expand Down
6 changes: 1 addition & 5 deletions Algorithm.Python/UniverseSelectionRegressionAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ def Initialize(self):


def CoarseSelectionFunction(self, coarse):
list = List[Symbol]()
for c in coarse:
if c.Symbol.Value == "GOOG" or c.Symbol.Value == "GOOCV" or c.Symbol.Value == "GOOAV" or c.Symbol.Value == "GOOGL":
list.Add(c.Symbol)
return list
return [ c.Symbol for c in coarse if c.Symbol.Value == "GOOG" or c.Symbol.Value == "GOOCV" or c.Symbol.Value == "GOOAV" or c.Symbol.Value == "GOOGL" ]


def OnData(self, data):
Expand Down
36 changes: 14 additions & 22 deletions Algorithm/QCAlgorithm.Python.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ public void AddData(Type dataType, string symbol, Resolution resolution, DateTim
/// <param name="pycoarse">Defines an initial coarse selection</param>
public void AddUniverse(PyObject pycoarse)
{
var coarse = ToFunc<IEnumerable<CoarseFundamental>, Symbol>(pycoarse);
AddUniverse(coarse);
var coarse = ToFunc<IEnumerable<CoarseFundamental>, object[]>(pycoarse);
AddUniverse(c => coarse(c).Select(x => (Symbol)x));
}

/// <summary>
Expand All @@ -114,9 +114,9 @@ public void AddUniverse(PyObject pycoarse)
/// <param name="pyfine">Defines a more detailed selection with access to more data</param>
public void AddUniverse(PyObject pycoarse, PyObject pyfine)
{
var coarse = ToFunc<IEnumerable<CoarseFundamental>, Symbol>(pycoarse);
var fine = ToFunc< IEnumerable<FineFundamental>, Symbol>(pyfine);
AddUniverse(coarse, fine);
var coarse = ToFunc<IEnumerable<CoarseFundamental>, object[]>(pycoarse);
var fine = ToFunc<IEnumerable<FineFundamental>, object[]>(pyfine);
AddUniverse(c => coarse(c).Select(x => (Symbol)x), f => fine(f).Select(x => (Symbol)x));
}

/// <summary>
Expand All @@ -128,8 +128,8 @@ public void AddUniverse(PyObject pycoarse, PyObject pyfine)
/// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
public void AddUniverse(string name, Resolution resolution, PyObject pySelector)
{
var selector = ToFunc<DateTime, string>(pySelector);
AddUniverse(name, resolution, selector);
var selector = ToFunc<DateTime, object[]>(pySelector);
AddUniverse(name, resolution, d => selector(d).Select(x => (string)x));
}

/// <summary>
Expand All @@ -140,8 +140,8 @@ public void AddUniverse(string name, Resolution resolution, PyObject pySelector)
/// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
public void AddUniverse(string name, PyObject pySelector)
{
var selector = ToFunc<DateTime, string>(pySelector);
AddUniverse(name, selector);
var selector = ToFunc<DateTime, object[]>(pySelector);
AddUniverse(name, d => selector(d).Select(x => (string)x));
}

/// <summary>
Expand All @@ -155,8 +155,8 @@ public void AddUniverse(string name, PyObject pySelector)
/// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
public void AddUniverse(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, PyObject pySelector)
{
var selector = ToFunc<DateTime, string>(pySelector);
AddUniverse(securityType, name, resolution, market, universeSettings, selector);
var selector = ToFunc<DateTime, object[]>(pySelector);
AddUniverse(securityType, name, resolution, market, universeSettings, d => selector(d).Select(x => (string)x));
}

/// <summary>
Expand Down Expand Up @@ -403,7 +403,6 @@ public PyObject History(PyObject tickers, DateTime start, DateTime end, Resoluti
/// Gets the symbols/string from a PyObject
/// </summary>
/// <param name="pyObject">PyObject containing symbols</param>
/// <param name="isEquity"></param>
/// <returns>List of symbols</returns>
public List<Symbol> GetSymbolsFromPyObject(PyObject pyObject)
{
Expand Down Expand Up @@ -465,26 +464,19 @@ private Type CreateType(PyObject type)
/// <typeparam name="TSecond">The output type</typeparam>
/// <param name="pyObject">The python method</param>
/// <returns>A <see cref="System.Func{T, TResult}"/> that encapsulates the python method</returns>
private Func<T, IEnumerable<TSecond>> ToFunc<T, TSecond>(PyObject pyObject)
private Func<T, TSecond> ToFunc<T, TSecond>(PyObject pyObject)
{
var testMod =
"from clr import AddReference\n" +
"AddReference(\"System\")\n" +
"AddReference(\"System.Collections\")\n" +
"AddReference(\"QuantConnect.Common\")\n" +
"from System import Func\n" +
"from System.Collections.Generic import IEnumerable\n" +
"from QuantConnect import Symbol\n" +
"from QuantConnect.Data.Fundamental import FineFundamental\n" +
"from QuantConnect.Data.UniverseSelection import CoarseFundamental\n" +
"def to_func(pyobject, in_type, out_type):\n" +
" return Func[in_type, IEnumerable[out_type]](pyobject)";
" return Func[in_type, out_type](pyobject)";

using (Py.GIL())
{
dynamic toFunc = PythonEngine.ModuleFromString("x", testMod).GetAttr("to_func");
return toFunc(pyObject, typeof(T), typeof(TSecond))
.AsManagedObject(typeof(Func<T, IEnumerable<TSecond>>));
return toFunc(pyObject, typeof(T), typeof(TSecond)).AsManagedObject(typeof(Func<T, TSecond>));
}
}
}
Expand Down

0 comments on commit 3da8449

Please sign in to comment.