Export a summary of performance stats by symbol programmatically
Author: Eugene
Creation Date: 2/26/2020 6:29 AM
profile picture

innertrader

#1
Hi Eugene,

I'm trying to understand what's going on programmatically in www2.wealth-lab.com/WL5WIKI/kbInteractingWithPortfolioEquity.ashx and https://www.wealth-lab.com/Forum/Posts/Trading-by-win-rate-and-profit-factor-32375/Page/1 so I can know how to adapt for my purpose.

After review of documentation, here's my first guess at what is going on. Please verify or correct.

Utility is a community components class that has a number of different methods, one of them being runDonor, and another being LoadStrategyFromDisk. The purpose of constructing code using this method is to get control of WL while it is running, so you can grab data by trade rather than letting it run normally and summarize. In the case of this example, it is to get access equity values and win / loss ratio on a trade by trade basis.

SystemPerformance (sp) appears to be the class that runs the strategy.
SystemResults (sr) is a class that uses the results from sp and also allows access to the resulting data, in the sample case, EquityCurve.

How would I know that a method like EquityCurve is available in SystemResults? The Wiki page for this class is not available to me. I'm wondering what other methods are available.

In thinking about it, the only code I require about closed positions is
CODE:
Please log in to see this code.

From this I should be able to generate winning % and average win / loss.

Can I comment out preceding code since I'm not interested in equity curve?

CODE:
Please log in to see this code.


and this code since I am not running a dependent strategy?

CODE:
Please log in to see this code.


Robert
profile picture

Eugene

#2
QUOTE:
How would I know that a method like EquityCurve is available in SystemResults? The Wiki page for this class is not available to me.

Robert, but it is available to you after logging in to the Wiki. Your Wiki account has the rights required to the page you're looking for at:

http://www2.wealth-lab.com/WL5WIKI/AllPages.aspx?Cat=API

QUOTE:
Can I comment out preceding code since I'm not interested in equity curve?

Correct.

QUOTE:
and this code since I am not running a dependent strategy?

Incorrect. With LoadStrategyFromDisk/runDonor methods you are running a "dependent strategy" so to say and quoted code helps the backtest performance by caching the results into global memory.
profile picture

innertrader

#3
Hi Eugene,

I see how the core code in the example creates a list of all Positions and how I can extract specific results (e.g., NP%) for these closed trades. I have confirmed that the performance results this approach yields exactly matches the donor strategy when run alone.

Since the Positions are stored in the list in date order, similar to the Trades tab, I'd like to figure out the best way to end up with something similar to the "By Symbol" tab results after a run. It would include Net Profit % for each symbol in addition to (# of) Trades and Pct Winners. I want to export the summarized performance to a file sorted by by symbol.

For a multi-position run, are there any best-practice examples you are aware of that show how I can do this?

Robert
profile picture

Eugene

#4
Hi Robert,

QUOTE:
For a multi-position run, are there any best-practice examples you are aware of that show how to summarize the results for each symbol?

Sorry, nothing comes to mind but you can always find some inspiration in (legacy) source code of MS123 Visualizers.
profile picture

innertrader

#5
HI EUgene,

I am able to create a list (dupList) that contains only the symbols of the positions. Now I am trying to eliminate the duplicates so I have a list of unique symbols.

I found the "Distinct" function that is supposed to extract only unique values from a list but it creates compile errors (CS0012, CS1061).

CODE:
Please log in to see this code.


I added
CODE:
Please log in to see this code.
at the beginning, and WL offers dupSymbols.Distinct when typing in. Don't know if the Distinct function is causing a problem or if there is something wrong with my syntax.

More detail on my CS1061 error:"'System Collections Generic.List<string> does not contain a definition for 'Distinct' and ...."
profile picture

Eugene

#6
You have to add a reference to System.Core for LINQ to work. On how to do it please refer to the WL User Guide > Strategy Window > Strategy Window Views > Editor: References...
profile picture

innertrader

#7
Thank you. Checking the System.Core reference got rid of the CS1061 error. I still have the CS0012 error. (I had assumed the resolution was related to the first error.)

QUOTE:
error CS0012: The type 'System.Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'


Is there another reference I have to include? I found multiple hits on Web search,but not sure if they apply, or how I would address them in the context of WL
profile picture

Eugene

#8
It's a well known bug since 6.9.20 but I think it's fixed in 6.9.23 beta as I don't see it there. Here's workaround for the production version 6.9.22:

WLP 6.9.20.7: New Editor has compiler error with LINQ methods, post #3
profile picture

innertrader

#9
That worked. Thanks!
profile picture

Eugene

#10
Glad to hear it works for you.
profile picture

innertrader

#11
My goal is to export a summary of performance stats by symbol (multi, dataset), programmatically. Apparently there is no mainstream way to do this in WL. Aspects of the code I hacked at https://www.wealth-lab.com/Forum/Posts/Exporting-values-to-CSV-file-29683 exposes the results of each closed trade of the "donor" strategy. These individual trades can then be summarized in the program to match the output of the Performance tab of the donor strategy of an individual symbol. And they do. It works!

QUOTE:
If your goal is to create a sorted listing of ClosedPositions by stock symbol, you could certainly sort the sr.Positions object instead to avoid the for loop.

My goal is not a sorted listing but a summarized export of performance by symbol (not individual trades). I decided I first had to know what symbols were included in the set (dupSymbols) and then dedup that list into unique symbols (uSymbols) so that I could go back and operate on the data with the symbol name being my filter for creating a performance summary for each symbol. And that all worked fine.

What I didn't realize is this code is not intended for multi symbol backtests and now I think I understand why. I believe now that the code execution is actually looping through the entire program for each symbol in the donor dataset, even though the first pass yields all the information I want. That's why if I have 4 symbols in the dataset, I am getting 4 duplicate sets of output in the export file.I believe I have confirmed that the entire program is being run 4 times, in this case, meaning StreamWriter is exporting the same data 4 times given the program logic.

My grasp of C# is not nearly strong enough to understand how I can break this cycle. I am guessing that the logic restarts at the Execute() statement each time it reads a new symbol from the dataset. I was wondering if I could set up a persistent variable (the would not be reset at Execute() ) to test for the run count and exit after the first one.

If there's no way to break the loop within a loop issue, I was wondering if outputting data to an array, and then indexing and feeding StreamWriter the data up to index < ClosedPositionsCount would ignore the excess data. Not elegant, but could work.
CODE:
Please log in to see this code.


Yes, you are right that I did eliminate this code because I didn't think (or know if) it was relevant. i am not trying to run a strategy based on a strategy but rather repurposing the methods presented to extract results by symbol in a way that I cannot otherwise get to.

Now that I've explained what I'm trying t accomplish, do you still think that putting this code back in would address the issue?
profile picture

Eugene

#12
My feeling is that your project changes direction from day to day. From your post dated 2/16/2020, "I would like to programmatically export a Kelly statistic from a backtest." For this reason you tried to export/construct the Win Rate and Payoff ratio. Now you state that "My goal is to export a summary of performance stats by symbol (multi, dataset), programmatically. (...) My goal is not a sorted listing but a summarized export of performance by symbol (not individual trades)".

Let's clarify something about the unsupported tool you're trying to put to use. The documentation at Interacting Dynamically with Portfolio Level Equity is a bit incomplete since it doesn't include new changes that made the runDonor method legacy. The new and more clear methods are:

1. Run a Donor strategy to collect its portfolio performance (MSB)

CODE:
Please log in to see this code.


Example:

CODE:
Please log in to see this code.


So if your goal is to obtain a MSB Portfolio Simulation for a DataSet, you execute the first method on first symbol of your DataSet just once and export the results to a file just once. It contradicts with the way you're used to with WealthScript execution but since the details are encapsulated it only takes to accept this.

2. Run a Donor strategy to collect its performance in single symbol mode (SSB)

CODE:
Please log in to see this code.


Example:

CODE:
Please log in to see this code.


Now if you're after obtaining the results per symbol for a DataSet (i.e. not a portfolio backtest), execute this second example on each symbol and Append the results to the file. If a separate file is required for each symbol, don't append but write to a new file.

Is this more clear now? What method are you after?
profile picture

innertrader

#13
Hi Eugene. Thanks for the additional information.

QUOTE:
My feeling is that your project changes direction from day to day.

No, it hasn't. Goal has always been to either create a K% in the program **for each symbol** and export them to a file, or export the data necessary (win rate, payoff ratio) **by symbol** to create K% for each symbol externally. The confusion may have come because the first quote was an original, high-level description of the business problem, and the second was a more detailed description of how I later was trying to achieve it, specifically as a response to questions from @superticker.
QUOTE:
What method are you after?

By method, do you mean technically as in C#, or more generally as to the two alternatives above? Assuming the latter, I am interested in solution #2 but I want to do it for multiple individual symbols. I had somehow thought that I could run this code for ~ 60 symbols by clicking on the dataset folder, but now I understand (I think) it was not designed to work that way.

Are you suggesting the code in #2 would work if I clicked on each symbol individually within the folder and then ran the program 60 times? Maybe the program would run automatically each time I clicked on a new symbol. Or are you suggesting something else?

I attempted to replace my existing code with your sample #2 above. I get error messages like, 'WinRateTrader' does not include..... LoadStrategyFromDisk (or) ExecuteStrategySSB as a definition or extension." I also get an error message "'MyStrategy' and 'MyStrategyName' does not exist in this context." Obviously something is wrong. Do I need an additional include for these methods to be recognized? Code snippet below.
CODE:
Please log in to see this code.
profile picture

Eugene

#14
C# is case sensitive and your compile errors might not occur if you carefully reviewed the case of your variables. Once you fix this it should be fine.

On a closing note, appreciate your understanding that you're dealing with unsupported internal methods. It's supposed that users experiment with them on their own. Even though it's not part of WealthScript, there are numerous examples on the forum.

I have nothing else to comment. Good luck with your project!
profile picture

innertrader

#15
Eugene - I'm mortified. And gratified! Thanks for the help you have provided thus far.

Robert
profile picture

Eugene

#16
Robert, you're welcome.
profile picture

innertrader

#17
@Eugene in case it is useful to anyone, I have completed a mod to your work that exports the performance results by symbol for a donor strategy from disk run against a Dataset of multiple symbols. This useful for exporting data by symbol, e.g., to grab the Kelly statistic by symbol, on a large number of symbols. This program saves a TXT file to the user folder path on a Windows 10 computer. It is only capturing long positions. Sample output attached and code below.

Thanks again for your help in moving me forward with this unsupported code.

CODE:
Please log in to see this code.
.

profile picture

Eugene

#18
Nice mod. Thanks for sharing your script with the Wealth-Lab community.
profile picture

KGo

#19
The above is a very nice method for by symbol analysis. For those interested in this topic here is another approach requiring only one line of code added to a strategy to save the trades.
https://www.wealth-lab.com/Forum/Posts/New-By-Symbol-Analysis-Available-40088/
profile picture

innertrader

#20
Hi Eugene,

Do you know if there is a method to access the signal status (Long / Short, Open / Closed) for each symbol in a Dataset programmatically, similar to what was done above for performance by symbol?

Robert
profile picture

Eugene

#21
What is a signal?
profile picture

innertrader

#22
What I mean by "signal" is whether a symbol has an Open position on the last (latest) day of a backtest. (Maybe the term "Open Status" would be more specific to not be confused with a single, date-specific, event.) And if it is Open, report whether it is a Long or Short position.

This could be also determined if there is programmatic access to the data shown in the Trades tab columns, "Position", "Entry Date", and "Exit Date", for each position, by simply checking whether most recent date lists "Exit Date" as "Open".
profile picture

superticker

#23
QUOTE:
This could be also determined if there is programmatic access to the data shown in the Trades tab columns, "Position", "Entry Date", and "Exit Date", for each position, by simply checking whether most recent date lists "Exit Date" as "Open".
Well, you can capture the Trades tab into the Windows clipboard, then use Excel or your own C# program to read the clipboard. For C#, use a StringReader datatype to read one line (record) of the clipboard at a time. You can then parse those lines into your own C# data structure.
CODE:
Please log in to see this code.

If you don't like parsing a tab delimited clipboard record (i.e. line) yourself, there are many other file reader choices (FileHelpers, ExcelReader) that can do that for you instead of StringReader. But StringReader is simplest to use with a little parsing of your own. I have an example using RegExp's to parse a captured account table (one record at a time) from ATP if you're interested.
profile picture

Eugene

#24
@innertrader

But you have access to the Positions list of the SystemResults object and can query the properties of a Position, including .Active, .PositionType and so on:

CODE:
Please log in to see this code.
profile picture

innertrader

#25
Uh. Yeah....

Thanks, Eugene, you saved me a lot of time. Already got it working.

Robert
profile picture

Eugene

#26
It was nothing. Glad to help.
profile picture

innertrader

#27
I recently tried running the program above in the Strategy Monitor (SM) but it didn't execute (manually from SM or automated schedule). I reviewed other Forum threads re: strategies not running in Strategy Monitor, but they didn't seem relevant to a strategy that runs a child strategy.

I tried doing some lightweight debugging and PrintDebug commands are not being executed in the parent strategy when it is run from SM. So I assume it is exiting before executing. (No error messages).

I realize the above program is unsupported but with what you know about how WL works, do you know that a parent-child strategy will not work from SM? Are there any other troubleshooting ideas you can share?
profile picture

Eugene

#28
If it runs outside of the Strategy Monitor (i.e. in Strategy window) then it's perfectly fine with me. File I/O in the SM is possible. As the other code which powers the strategy above from Community Components is open source, please consider doing your own troubleshooting as suggested in the KB article: How can I debug my trading strategies in Wealth-Lab?
This website uses cookies to improve your experience. We'll assume you're ok with that, but you can opt-out if you wish (Read more).