문제

I'm playing around with historical stock market analysis in Perl. One aspect deals with analyzing the accuracy of research firms past stock ratings. The most rudimentary rating scale would be Buy, Hold, Sell. However many of these firms use different terminology, some with more than 3 points on their scale.

What I have is a list of thousands of upgrade/downgrades issued by hundreds of different firms (from Yahoo Finance) that looks something like this:

Action      From      To
==================================================
Upgrade     Add           Buy
Downgrade   Add           Hold
Upgrade     Hold          Add
Downgrade   Buy           Outperform
Upgrade     Hold          Outperform
Downgrade   Hold          Reduce
Upgrade     Add           Outperform

So basically it's a list of comparisons like A > B, D < C, B > C, D < A

What I need for each research firm, taking in a long list of these comparisons, is an ordered list that looks like this:

A > B > C > D > E

I've given this problem a lot of thought and can't come up with a solution. If each upgrade/downgrade only jumped one increment, I think I could do it but I can't wrap my head around how to insert a comparison like C < A, where it jumps two increments.

Anybody have any ideas?




Update:

Thanks @ikegami. I tested with the original data and you are correct.

I also ran some data through Graph::Easy, which renders graphs.

Code:

use Graph::Easy;
my $graph = Graph::Easy->new( );

# Note that these are all in 'Upgrade' direction
$graph->add_edge ('Hold', 'Add');
$graph->add_edge ('Hold', 'Buy');
$graph->add_edge ('Hold', 'Outperform');
$graph->add_edge ('Buy', 'Outperform');
$graph->add_edge ('Reduce', 'Hold');
$graph->add_edge ('Add', 'Buy');

print $graph->as_ascii( );

Output:

               +------------------------+
               |                        v
+--------+     +------+     +-----+     +-----+     +------------+
| Reduce | --> | Hold | --> | Add | --> | Buy | --> | Outperform |
+--------+     +------+     +-----+     +-----+     +------------+
               |                                    ^
               +------------------------------------+

Here's a graph with some clear ambiguities. Perhaps I can somehow use both modules (or some feature of Graph) to test for ambiguities.

+------------------------------+
|                              v
+--------+     +---------+     +-----+
| Reduce | --> | Neutral | --> | Buy |
+--------+     +---------+     +-----+
                 ^               ^
                 |               |
                 |               |
               +---------+       |
               |  Sell   | ------+
               +---------+
도움이 되었습니까?

해결책

I don't use graphs all that often, but this code (using the Graph module) seems to do the job:

use Graph;
use strict;

my $graph = Graph->new;

while (<DATA>) {
    my ($dir, $x, $y) = split;
    if ($dir eq 'Downgrade') {
        ($x, $y) = ($y, $x);
    } elsif ($dir ne 'Upgrade') {
        die qq(Unknown direction "$dir"\n);
    }
    $graph->add_edge($x, $y);
}

$graph->is_dag
    or die "Graph has a cycle--unable to analyze\n";
$graph->is_weakly_connected
    or die "Graph is not weakly connected--unable to analyze\n";

print join(' < ', $graph->topological_sort), "\n";

__DATA__
Upgrade     Add           Buy
Downgrade   Add           Hold
Upgrade     Hold          Add
Downgrade   Buy           Outperform
Upgrade     Hold          Outperform
Downgrade   Hold          Reduce
Upgrade     Add           Outperform

This prints Reduce < Hold < Add < Outperform < Buy.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top