Amibroker-OLE-Interface

 view release on metacpan or  search on metacpan

lib/Amibroker/OLE/APXCreator.pm  view on Meta::CPAN

package Amibroker::OLE::APXCreator;

use 5.006;
use strict;
use warnings;
use Path::Tiny;
use File::Slurp;
use Carp;
use IO::File;

=head1 NAME

Amibroker::OLE::APXCreator - A simple interface to create .apx extension file for accessing Amibroker analysis document from external scripts.

=head1 VERSION

Version 0.03

=cut

our $VERSION = '0.03';

=head1 SYNOPSIS

	use Amibroker::OLE::APXCreator;
	my $new_apx_file = create_apx_file( {
                                        afl_file   => 'test_afl.afl',
                                        symbol     => 'ADANIPORTS-I',
                                        timeframe  => '20-minute',
                                        from       => '01-09-2015',
                                        to         => '20-09-2015',
                                        range_type => 0,
                                        apply_to   => 1
                                    } );

=head1 DESCRIPTION

This module helps in creating apx file (i.e. file with .apx extention), which is the basic input file for running Amibroker analysis externally through OLE automation.

Creating this file automatically is a challenge as Amibroker is very sensitive to any changes with respect to apx file.
If there is even a space missed in creating it, then it will not process it.
So, to make life easier, this module handles the creation of the file as required by the amibroker.

NOTE: Please ensure to provide all the required necessary fields.

	use Amibroker::OLE::APXCreator;
	my $new_apx_file = create_apx_file( {
                                        afl_file   => 'path_to_the_location_of_the_afl_file',
                                        symbol     => 'symbol_name',
                                        timeframe  => 'timeframe',
                                        from       => 'from_date',
                                        to         => 'to_date',
                                        range_type => range_type_in_number,
                                        apply_to   => apply_to_in_number
                                     } );

=head2 REQUIRED PARAMETERS

=over 8

=item B<afl_file>

Complete Path to the AFL file, that you need to backtest or optimize or scan etc.
Eg: afl_file => 'C:/Amibroker/Stratergy/Release/IBM.afl'

=item B<symbol>

The Symbol name should match with the symbol names in the Amibroker database
Eg: symbol => 'IBM-I' or
    symbol => 'IBM'
    (The name should exactly match with your database symbol)  

=item B<timeframe>

    Default available timeframe with Amibroker.
    yearly    
    quarterly  
    monthly   
    weekly    
    daily     
    day/night 
    hourly     
    15-minute 
    5-minute 
    1-minute   
    3-minute 
    7-minute  
    10-minute
    12-minute 
    20-minute 

If you want to have your custom defined timeframe then you need to update here
Amibroker -> Tools -> Preferences -> Intraday Tab -> Custom Time Intervals

=item B<from>

    from date, Eg: from => '01-12-2010' (for 1st December 2010 date)
                   from => '2010-12-01' (for 1st December 2010 date)
                   from => '2010-01-12' (for 1st December 2010 date)
                   from => '12-01-2010' (for 1st December 2010 date)
                   from => '12-2010-01' (for 1st December 2010 date)
Date format should match your Amibroker date format : Usually it is windows system time settings
Please check your amibroker date format and send the appropriate date format

=item B<to>

    to date, Eg: to => '31-05-2015' (for 31st May 2015 date)
Date format should match your Amibroker date format : Usually it is windows system time settings
Please check your amibroker date format and send the appropriate date format

=item B<apx_file>

complete path of the apx file where you want to create this file.
    Eg: apx_file => 'C:/IBM.apx'

=item B<range_type>

    Range in Amibroker analysis refers to
        'All Quotes'      = 0  
        '1 recent bar(s)' = 1
        '1 recent day(s)' = 2
        'From-To-dates'   = 3
    So provide range number accordingly

=item B<apply_to>

    Apply the settings to
	   '*All Symbols' = 0
	   '*Current'     = 1
	   '*Filter'      = 2

=back

=head2 OPTIONAL PARAMETERS

=over 1

=item B<periodicity>

This module assumes that there is no change in the amibroker custom time interval settings.
i.e Amibroker -> Tools -> Preferences -> Intraday Tab -> Custom Time Intervals.

Amibroker assigns a value to every intervals  
    Eg: (Below are the default Amibroker intervals provided and their default values)
    yearly     = -4
    quarterly  = -3
    monthly    = -2
    weekly     = -1
    daily      =  0
    day/night  =  1
    hourly     =  2
    15-minute  =  3
    5-minute   =  4
    1-minute   =  5
    3-minute   = 10
    7-minute   = 11
    10-minute  = 12
    12-minute  = 13
    20-minute  = 14

If you happen to change the custom time intervals, then the amibroker default values may change.
In that case you have to find out the actual value of the custom interval and pass as the parameter.

    Eg:
    periodicity => -5 
    (you can find this out by manually saving the apx file and checking the periodicity field)

How to create apx file manually:

=over 3 

=item * Open Amibroker -> Analysis window -> Settings

=item * Edit settings as per your requirement

=item * Menu-> File-> Save_AS -> select (.apx extenstion)

=back

For more infor on apx file, check this forum : L<http://amibrokerforum.proboards.com/thread/57/analysis-project-files-apx>

=back

=cut

#
# Create the apx file that goes as input to the amibroker engine
#
my %periods = (
    'yearly'    => -4,
    'quarterly' => -3,
    'monthly'   => -2,
    'weekly'    => -1,
    'daily'     => 0,
    'day/night' => 1,
    'hourly'    => 2,
    '15-minute' => 3,
    '5-minute'  => 4,
    '1-minute'  => 5,
    '3-minute'  => 10,
    '7-minute'  => 11,
    '10-minute' => 12,
    '12-minute' => 13,
    '20-minute' => 14
);

sub create_apx_file {
    my @list = @_;
    my $args = _check_valid_args(@list);
    if ( !$args->{timeframe} ) {
        croak( '[ERROR}: No timeframe passed (Required parameter) : ' . "\n" );
    }
    if ( !$args->{periodicity} ) {
        $args->{periodicity} = lc( $args->{timeframe} );
    }
    if ( !$args->{periodicity} ) {
        croak(  '[ERROR}: No periodicity found for given timeframe '
              . $args->{timeframe}
              . "\n" );
    }
    if ( !-e $args->{afl_file} ) {
        croak( '[ERROR}: AFL file not present at:' . $args->{afl_file} . "\n" );
    }
    if ( !$args->{symbol} ) {
        croak( '[ERROR}: Symbol name not passed (Required parameter):' . "\n" );
    }
    if ( !$args->{from} ) {
        croak(
            '[ERROR}: from date is not passed (Required parameter):' . "\n" );
    }
    if ( !$args->{to} ) {
        croak( '[ERROR}: to date is not passed (Required parameter):' . "\n" );
    }
    if ( !$args->{apx_file} ) {
        print
'[WARN]: apx_file is not passed, by default your apx file name will be : C:/'
          . $args->{symbol} . '.apx' . "\n";
        $args->{apx_file} = 'C:/' . $args->{symbol} . '.apx';
    }
    if ( !defined( $args->{range_type} ) ) {
        croak(  '[ERROR}: range_type value is not passed, (Required parameter):'
              . "\n" );
    }
    if ( !defined( $args->{apply_to} ) ) {
        croak(  '[ERROR}: apply_to value is not passed, (Required parameter):'
              . "\n" );
    }
    my $text_dummy = 'XXXX';

    $args->{from} = $args->{from} . ' 00:00:00';
    my $afl_data = slurp_afl( $args->{afl_file} );
    $args->{afl_file} =~ s/\//\\/gx;
    $args->{afl_file} =~ s/\\/\\\\/gx;
    my $afl = convert_afl_text_for_amibroker($afl_data);
    my $fh  = IO::File->new("> $args->{apx_file}");
    while ( my $data = <DATA> ) {
        $data =~ s/
                    \<Symbol\>
                    $text_dummy
                    \<\/Symbol\>
                    /
                    \<Symbol\>
                    $args->{symbol}
                    \<\/Symbol\>
                 /gx;
        $data =~ s/
                    \<FormulaPath\>
                    $text_dummy
                    \<\/FormulaPath\>
                  /
                    \<FormulaPath\>
                    $args->{afl_file}
                    \<\/FormulaPath\>
                  /gx;
        $data =~ s/
                    \<FormulaContent\>
                    $text_dummy
                    \<\/FormulaContent\>

lib/Amibroker/OLE/APXCreator.pm  view on Meta::CPAN

                    \<ToDate\>
                    $args->{to}
                    \<\/ToDate\>
                 /gx;
        $data =~ s/
                    \<ApplyTo\>
                    $text_dummy
                    \<\/ApplyTo\>
                  /
                    \<ApplyTo\>
                    $args->{apply_to}
                    \<\/ApplyTo\>
                 /gx;
        $data =~ s/
                    \<RangeType\>
                    $text_dummy
                    \<\/RangeType\>
                  /
                    \<RangeType\>
                    $args->{range_type}
                    \<\/RangeType\>
                /gx;
        print $fh $data;
    }
    undef $fh;    # automatically closes the file
    autoflush STDOUT 1;
    return $args->{apx_file};
}

#
# Gulp the file into a string
#
sub slurp_afl {
    my $text = File::Slurp::read_file(shift);
    return $text;
}

#
# Convert text that is gulped into a scalar variable and modifiy accordingly to be loaded to Amibroker.
#
sub convert_afl_text_for_amibroker {
    my $text = shift;
    $text =~ s/\&/\&amp\;/g;
    $text =~ s/\\n/\\\\n/g;
    $text =~ s/\R/\\r\\n/g;
    $text =~ s/\t/\\t/g;
    $text =~ s/\</\&lt\;/g;
    $text =~ s/\>/\&gt\;/g;
    unless ( $text =~ /\\r\\n$/ ) {
        $text =~ s/$/\\r\\n/g;
    }
    return $text;
}

sub _check_valid_args {
    my @list = @_;
    my %args_permitted = map { $_ => 1 } (
        qw|
          afl_file
          symbol
          timeframe
          from
          to
          apx_file
          periodicity
          apply_to
          range_type
          |
    );
    my @bad_args = ();
    my $arg      = pop @list;
    for my $k ( sort keys %{$arg} ) {
        push @bad_args, $k unless $args_permitted{$k};
    }
    croak("Unrecognized option(s) passed to Amibroker OLE: @bad_args")
      if @bad_args;
    return $arg;
}

=head1 AUTHOR

Babu Prasad HP, C<< <bprasad at cpan.org> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-amibroker-ole-apxcreator at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Amibroker-OLE-APXCreator>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Amibroker::OLE::APXCreator


You can also look for information at:

=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Amibroker-OLE-APXCreator>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Amibroker-OLE-APXCreator>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Amibroker-OLE-APXCreator>

=item * Search CPAN

L<http://search.cpan.org/dist/Amibroker-OLE-APXCreator/>

=back


=head1 ACKNOWLEDGEMENTS



( run in 1.564 second using v1.01-cache-2.11-cpan-e1769b4cff6 )