As far as I know, FinancialData does not provide a way to query the length of data available for a particular stock. The only way of knowing it is to query the data and select those that have data for 20 years. First, let's get a list of all NYSE stocks with:
stocks = FinancialData["NYSE:*", "Lookup"];
Now, I have multiple interpretations for your 20 year constraint, so I'll address them below.
1. The stock existed 20 years ago
This does not take into account if the stock exists at present. So, first we get the exact date 20 years ago with
date20yAgo = DatePlus[DatePlus[0], {-20, "Year"}];
and select those stocks that have data on that day. To account for that day being a Saturday/Sunday or any other public holiday, we retrieve data for the entire week:
existed20yAgo := ! FinancialData[#, {date20yAgo, DatePlus[date20yAgo, 7]}] ===
Missing["NotAvailable"] &;
Select[stocks[[ ;; 20]], existed20yAgo] // Quiet
(*
Out[1]= {"NYSE:AA", "NYSE:AAI", "NYSE:AAN", "NYSE:AAR", "NYSE:AB",
"NYSE:ABA", "NYSE:ABK", "NYSE:ABK-PZ", "NYSE:ABM", "NYSE:ABN-PE"}
*)
I've just retrieved for the first 20 so that it runs in a reasonable time when you're checking. For the full list, remove the call to Part.
2. The stock has existed for the past 20 years
You can simply modify the above example a little as:
existedForPast20y[stock_] :=
FreeQ[! (FinancialData[stock, {#, DatePlus[#, 7]}] ===
Missing["NotAvailable"]) & /@ {date20yAgo, DatePlus[-7]}, False]
You can do a quick check of the above with:
existedForPast20y /@ {"AAPL", "GOOG"}
(* Out[2]= {True, False} *)
You can use Select[...] as before and use this function to test.
3: The stock has 20 years of historical data (any date range)
This will unfortunately require pulling all the data for each stock, and will definitely be slower.
has20yData := DateDifference[Sequence @@ (First /@
Through[{First, Last}[FinancialData[#, All]]]), "Year"][[1]] >= 20 &
Again, replace the test function in Select with has20yData. I'll leave the rest of the constraints for you to work on.