1. 首页
  2. 易语言 - EasyLanguage
  3. Classes
  4. 全局字典 GlobalDictionary Class
  1. 首页
  2. 易语言 - EasyLanguage
  3. 全局字典 GlobalDictionary Class

全局字典 GlobalDictionary Class

本文介绍全局字典的概念、使用、命名空间、 初始化、属性、方法、事件和几个应用实例。

Overview

Description

A GlobalDictionary is an array-like collection object for storing string-indexed values of non-specific type.

sKey (Index)oValue (normal datatypes: bool, string, int, double, etc.), or Object
“myInt”3
“myDouble”12.5
“myBool”true
“myObj”myCollectionObject
“shirley”“stop calling me shirley”

It may help to think of a GlobalDictionary as an unsorted list.

A GlobalDictionary object allows you to set up a collection of key/value pairs that can be shared between EasyLanguage analysis techniques and strategies ( “studies” ). The GlobalDictionary class includes many of the same properties and methods as the Dictionary class.

GlobalDictionary extends the concept of Dictionary, by providing the additional ability to share its values between studies

  • “interprocess” sharing is the sharing of data between studies that are applied to different applications/window types 
    • Charting <-> RadarScreen
  • “intraprocess” sharing is the sharing of data between studies that are applied to the same application/window type** Charting <-> Charting
    • RadarScreen <-> RadarScreen

The important points about a GlobalDictionary are:

  • A GlobalDictionary’s size is dynamic ( doesn’t have a fixed size )
  • Each item ( “element” ) in the GlobalDictionary is referenced by a string index
  • To loop through elements in a GlobalDictionary, declare a Vector and assign GlobalDictionary.Keys to it
  • GlobalDictionary values can contain normal datatypes (such as integer, string, double, boolean), other Objects, or a mixture of all of the above
  • GlobalDictionary can be configured to share values calculated in one study ( the ‘sender’ ), so that they can be retrieved by another study ( the ‘receiver’ )
  • Instances of GlobalDictionary can be named or unnamed
    • Interprocess sharing requires that you use a named instance
    • A named GlobalDictionary instance should be thought of as “A GlobalDictionary”
    • Any unnamed GlobalDictionary instance should be thought of as a member of “The GlobalDictionary”
    • Unnamed instance members are NOT segregated from each other by instance or variable declaration

Important programming notes:

  • See the Initialization section, below
  • See the Usage Examples section, below
  • See the Limitations section, below

General Usage

GlobalDictionary is a variable type, which must be declared, as in:

variables: GlobalDictionary myGDict( null ) ;

Properly declared, it can be created in the code body with:

myGDict = New GlobalDictionary ;

or

myGDict = GlobalDictionary.Create() ;

Please note additional details below, in the Initialization section, regarding the .Create() method.

Elements are added to the GlobalDictionary using the .Add( sKey, oValue ) method, or the .Items[ sKey ] property, where sKey is a string containing the key name and oValue is the value to be stored.

Elements (key and value) are removed from the GlobalDictionary using the .Remove(sKey) method.

The .Contains( sKey ) method is used to determine if a key exists in the GlobalDictionary.

For more information about manipulating a GlobalDictionary object, see the Methods section, below.

For GlobalDictionary usage examples, see the Usage Examples section, below.

Namespace

GlobalDictionary is a collection class in the ‘elsystem.collections’ namespace.

The fully-qualified class name is ‘elsystem.collections.GlobalDictionary’.

Other members of the elsystem.collections class include:

Important Programming Notes:

  • The fully-qualified class name is ‘elsystem.collections.GlobalDictionary’
  • If you omit the ‘using elsystem.collections ;’ statement from the top of your code, any reference you make in code to the GlobalDictionary class ( and related event handler method arguments ) must be fully qualified
    • The following table illustrates this
‘Using elsystem.collections ;’ statement included‘Using elsystem.collections ;’ statement omitted
myGDict = New GlobalDictionary ;myGDict = New elsystem.collections.GlobalDictionary ;
method void myHandler( Object sender, ItemProcessedEventArgs args )method void myHandler( elsystem.Object sender, elsystem.collections.ItemProcessedEventArgs args )
  •  Best Practice: ALWAYS include the appropriate ‘using’ statement whenever your code uses EasyLanguage classes

Initialization, Properties, Methods, Events

Initialization

There are three ways the GlobalDictionary can be configured.

  1. An unnamed GlobalDictionary instance can be configured to share normal datatypes or objects within the same window type ( “intraprocess” sharing )
    • Charting <-> Charting
    • RadarScreen <-> RadarScreen
    • but not Charting <-> RadarScreen
  2. named GlobalDictionary instance can be configured to share normal datatypes or objects within the same window type ( “intraprocess” sharing )
  3. named GlobalDictionary can be configured to share normal datatypes between window types ( “interprocess” sharing ) 
    • Charting <-> RadarScreen

To create an unnamed instance of GlobalDictionary for intraprocess sharing of values or objects:

using elsystem.collections ;

variables: GlobalDictionary myGDict( NULL ) ;

myGDict = GlobalDictionary.Create() ;
// {OR} myGDict = New GlobalDictionary ;

To create a named instance of GlobalDictionary for intraprocess sharing of values or objects:

using elsystem.collections ;

variables: GlobalDictionary myGDict( NULL ) ;

myGDict = GlobalDictionary.Create( FALSE, "myGDictName" )

To create a named instance of GlobalDictionary for interprocess sharing of values:

using elsystem.collections ;

variables: GlobalDictionary myGDict( NULL ) ;

myGDict = GlobalDictionary.Create( TRUE, "myGDictName" ) ;

Important Programming Notes:

  • If the Share parameter of the .Create() method is specified, then both the ‘sender’ and the ‘receiver’ studies must declare a GlobalDictionary with the same name parameter – see the Usage Examples section, below
  • The Share parameter value of TRUE or FALSE ( see overloaded .Create method, below ) controls whether interprocess sharing is enabled or disabled
  • If the .Create() method is used without any parameters ( equivalent to = New GlobalDictionary ; ), sharing is intraprocess by definition
    • In this case, ‘Receiver’ access to GlobalDictionaries is a bit of a free-for-all ( see Usage Example #2, below )
  • As with all Classes, myGDict is automatically declared as IntrabarPersist

Properties

NameTypeDescriptionUsage Example
.Count<int>Gets the the number of elements contained in the GlobalDictionaryget: myInteger = myGDict.Count() ;
.Items<string>Gets or sets the value of the element with the specified keyget: myValue = myGDict.Items[ “myItem” ] astype …;
set: myGDict.Items[ “myItem” ] = myValue ;
.Keys<vector>Gets the vector collection of sorted keys from the GlobalDictionaryget: myVector = myGDict.Keys ;
.Values<vector>Gets the vector collection of sorted values from the GlobalDictionaryget: myVector = myGDict.Values ;

Important Programming Notes:

  • The following two statements are equivalent
    • myGDict.Add( “myKey”, Value1 ) ; ( see Methods section, below )
    • myGDict.Items[ “myKey” ] = Value1 ;
  • See the Vector class page for more information about how to declare and use a Vector class object
  • Note that the Vector returned by the .Keys or .Values property is sorted alphanumerically by Key or Value

Methods

NameDescriptionUsage Example 
.Add( string Key, object Value )Adds an element with the provided Key and Value to the collectionmyGDict.Add( “myKey”, Value1 ) ; 
.Clear()Removes all elements from the collectionmyGDict.Clear() ; 
.Contains( string Key)True if the collection contains an element with the specified KeymyBool = myGDict.Contains( “myKey” ) ; 
.Create()Initializes a new instance of the collection
( equivalent to Reserved Word “New” )
myGDict.Create() ;
-or-
myGDict = New GlobalDictionary ;
 
.Create( bool Share, string Name )Initializes a new, shared instance of the collection
Share FALSE: for intraprocess sharing
Share TRUE: for interprocess sharing
.
myGDict = GlobalDictionary.Create( FALSE, “myGDictName” ) ;
myGDict = GlobalDictionary.Create( TRUE, “myGDictName” ) ;
 
.Remove( string Key )Removes the element with the specified Key from the collectionmyGDict.Remove( “myKey” ) ; 

 Important Programming Notes:

  • The .Create() method is important to understand
    • See the sections Initialization and Limitations, below
  • The following two statements are equivalent
    • myGDict.Add( “myKey”, Value1 ) ;
    • myGDict.Items[ “myKey” ] = Value1 ; ( see Properties section, above )
  • The .Items set property quietly calls the .Add method if the key does not already exist, which makes .Items more flexible, while using less code ( less manual exception handling ). However, if you wish an exception to be thrown when re-adding an existing key, use the .Add method.

Events

NameFires…Handler DeclarationHandler Method Arguments
.Clearedwhenever the collection is clearedmyGDict.Cleared += ‘method name’method void ‘method name’ ( Object sender, ItemProcessedEventArgs args )
.ItemAddedwhen an item is added to the collectionmyGDict.ItemAdded += ‘method name’method void ‘method name’ ( Object sender, ItemProcessedEventArgs args )
.ItemChangedwhen an item is added to or changed in the collectionmyGDict.ItemChanged += ‘method name’method void ‘method name’ ( Object sender, ItemProcessedEventArgs args )
.ItemDeletedwhen an item is removed from the collectionmyGDict.ItemDeleted += ‘method name’method void ‘method name’ ( Object sender, ItemProcessedEventArgs args 

Usage Examples

Usage Example #1

The following example demonstrates interprocess sharing of data using GlobalDictionary.

‘Sender’ Indicator ( interprocess sharing )

using elsystem.collections ;

variables:
     intrabarpersist double mySendVal( 0 ),

     GlobalDictionary myGDict( null )
     ;


method void UpdateGDict()
begin
     myGDict.Items[ "sharedVal" ] = mySendVal ;
     PlotOutput() ;
end ;


Once begin
     myGDict = GlobalDictionary.Create( true, "myGDictName" ) ;
end ;


mySendVal = Close ;
UpdateGDict() ;

‘Receiver’ Indicator (interprocesssharing )

using elsystem.collections ;

variables:
     intrabarpersist double myReceivedVal( 0 ),

     GlobalDictionary myGDict( null )
     ;


method void PlotOutput()
begin
     Plot1( myReceivedVal, "RecvVal" ) ;
end ;Once begin

     myGDict = GlobalDictionary.Create( true, "myGDictName" ) ;

end ;


myReceivedVal = myGDict.Items[ "sharedVal" ] astype double ;

Value1 = close ;

Sample Result:

Notes:

  • ‘Sender’ in this example should be applied to a Chart
  • ‘Receiver’ in this example should be applied to a RadarScreen
  • Note that both ‘Sender’ and ‘Receiver’ declare a named instance of GlobalDictionary, and that the name used in both cases is identical; this is a critical requirement for interprocess sharing
  • ‘Sender’ captures the Close of the Symbol on the Chart to which it is applied, and places this value into myGDict, at element index “sharedVal”
  • ‘Receiver’ polls myGDict for the value at element index “sharedVal” on startup, and every tick thereafter ( without Value1 = Close, it would only do this on startup and ‘on close’ )
  • ‘Receiver’ is applied to a RadarScreen, whose symbols and intervals are irrelevant, except for the following subtleties:
    • the Interval of the RadarScreen symbol defines the ‘when’ in the previous bullet’s ‘evey tick’ and ‘on close’ statements ( see also Best Practices, below )
    • the decimal precision of the the received value plotted in RadarScreen is inherited from the symbol to which the study is applied ( see screenshot )
  • The ‘astype double’ statement in ‘Receiver’ is necessary because we we need to cast the object type from the GlobalDictionary into a type that is compatible with the variable to which this object is being assigned, which is a double type
    • If we wanted to retrieve the value of “sharedVal” as a string ( presupposing that we had declared a variable of type string to hold it ) we could not use ‘astype string’
      • Instead, we use the .ToString() method, which is a built-in method of all elsystem.object objects, as follows:
      • myReceivedVal = myGDict.Items[ sharedVal ].ToString() ;
  • Best Practices:
    • Use named instances of GlobalDictionary whenever possible
      • You must use a named instance for interprocess sharing
      • If you add a Timer object to a GlobalDictionary, you must use an unnamed instance
      • ALL unnamed instances of GlobalDictionary are the same GlobalDictionary
        • all elements from all unnamed GlobalDictionary instances are accessible by Key name from any study within a given application type
        • This means that myGDict1[ “item1” ] and myGDict2[ “item1” ] are the same ‘Item’
        • see Usage Example #2 below for an illustration
    • Use intraprocess sharing whenever possible
      • See the Limitations section, below
    • Use an event handler to control plotting by the ‘Receiver’, such as the GlobalDictionary.ItemChanged or the Timer.Elapsed event
      • This will tighten-up your results; notice the price discrepancy above between the Sent value ( EURUSD ) and the Received value ( GBPUSD )
        • This occured because ‘Receiver’s update schedule, based on the sample code above, is ‘on startup’ and ‘every tick thereafter’ of GBPUSD
        • ‘Sender’s update schedule is every tick of EURUSD
      • This will help avoid the run-time error, InvalidCastException: Unable to cast NULL object, which occurs if the ‘Receiver’ tries to plot before the ‘Sender’ has placed a value into the GlobalDictionary
      • When exceptions like this are thrown, often you can fix the code, re-verify, and then toggle the symbol to recover ( instead of having to remove/re-apply the study )
        • If you suspect questionable results after doing this, remove and re-apply the study
      • GlobalDictionary.ItemChanged does not fire unless the Value at index sKey is added or changed
        • If a GlobalDictionary item is another collection, such as a Vector, and an item within the Vector changes, GlobalDictionary.ItemChanged does not fire
        • If as item is removed from the GlobalDictionary, GlobalDictionary.ItemChanged does not fire; GlobalDictionary.ItemDeleted fires instead

Usage Example #2

The following example demonstrates intraprocess sharing of data using GlobalDictionary.

‘Sender’ Indicator ( intraprocess sharing )

using elsystem.collections ;

variables:
	intrabarpersist double mySendVal1( 0 ),
	intrabarpersist double mySendVal2( 0 ),

	GlobalDictionary myGDict1( null ),
	GlobalDictionary myGDict2( null )
	;

method void PlotOutput()
begin

	Plot1( Close, "SendVal" ) ;
	Plot2( Open, "SendVal" ) ;

end ;

method void UpdateGDict()
begin

	myGDict1.Items[ "1sharedVal" ] = mySendVal1 ;
	myGDict2.Items[ "2sharedVal" ] = mySendVal2 ;

	PlotOutput() ;

end ;



Once begin

	myGDict1 = GlobalDictionary.Create() ;
	myGDict2 = GlobalDictionary.Create() ;

end ;


mySendVal1 = Close ;
mySendVal2 = Open ;

UpdateGDict() ;

‘Receiver’ Indicator (intraprocesssharing )

using elsystem.collections ;

variables:
	intrabarpersist double myReceivedVal1( 0 ),
	intrabarpersist double myReceivedVal2( 0 ),

	GlobalDictionary myGDict( null )
	;


Once begin

	myGDict = GlobalDictionary.Create() ;

end ;


myReceivedVal1 = myGDict.Items[ "1sharedVal" ] astype double ;
myReceivedVal2 = myGDict.Items[ "2sharedVal" ] astype double ;

Plot1( myReceivedVal1, "RecvVal1" ) ;
Plot2( myReceivedVal2, "RecvVal2" ) ;

Value1 = close ;

Notes:

This example is similar to Exampe #1 above, with a few important differences:

  • Both ‘Sender’ and ‘Receiver must be applied to the same application type
  • The ‘Sender’ declares two unnamed instances of GlobalDictionary, while the ‘Receiver’ declares a single unnamed instance
    • Yet ‘Receiver’ has access to any of ‘Sender’s instances ( ‘myGDict1’ and ‘myGDict2’ )
  • Access to GlobalDictionaries by ‘Receiver’ and ‘Sender’ is therefore something of a free-for-all; the only requirement is that the requested Key is valid and contains a non-null value
  • You cannot add a Timer ( or any other object type ) to a named instance of a GlobalDictionary
    • A Timer ( or any other object type ) can only be added to an unnamed instance of GlobalDictionary
    • Members of unnamed GlobalDictionary instances are accessible via ANY unnamed instance of GlobalDictionary

Limitations

Known limitations as of January 2012 ( 9.1 Build 11704 )

  1. GlobalDictionary cannot be used to pass objects between window types. When the Share parameter is set to TRUE, the following statements about interprocess sharing apply:
    • When using GlobalDictionary to share data between studies, it is important to consider both the application type ( aka “window type” ) that hosts the study, and the type of data contained in the GlobalDictionary. Not all dataypes can be shared with all application types.
    • Charting is one application type, RadarScreen is another. In the context of GlobalDictionary, these two application types are distinct and you may not be able to share data between these application types, depending on the type of data the GlobalDictionary contains.
    • If Share is TRUE, then you can only add sKey/oValue pairs to the GlobalDictionary if oValue is a normal datatype ( int, string, bool, etc. ).
    • If Share is TRUE, and you try to add an object to GlobalDictionary, such as a Dictionary ( or any other collection object ), the code will compile, but you will receive a run-time error:
      • MissingMemberException: Class not serializable
    • This limitation is significant because it means that only normal datatypes can be shared between Charting and RadarScreen
  2. January 2012 update to Limitation #1 above
    • New in TradeStation 9.1: multi-core support for charting
    • When the multi-core support option is enabled:
      • Limitation #1 above becomes much more significant
      • the way we think about the difference between intraprocess vs. interprocess sharing changes drastically
      • this distinction no longer runs along the lines of sharing data between application window types ( Charting, RadarScreen )
      • intraprocess sharing is now available only in the following three circumstances:
        1. Multi-core support is disabled
        2. Multi-core support is enabled and the Sender and Receiver both reside in the same chart
        3. Multi-core support is enabled and both charts sharing a GD just happen to be, by chance, assigned to the same core
    • For all practical purposes, therefore, intraprocess sharing is DEAD
      • you want multi-core support, right ?!
      • you want to use a GD to share objects between charts, right ?!
      • Unless Limitation #1 above is eliminated, YOU CANNOT DO BOTH
      • if you got on the Object-Oriented bandwagon and re-wrote your array-based code to be vector-based code, and you share those objects using an intraprocess GD, you either have to convert back to using arrays, or you have to disable multi-core support
  3. GlobalDictionary read/write performance differs significantly, depending on the value of the Share parameter, as shown in the following table:
    • Note that each value below is expressed in terms relative to some minimum. For example, “1x” is the smallest unit of measure required to perform any operation, regardless of the operation being performed. A value of “2x” would therefore mean that the operation took twice as many units as the one that required “1x”.
    • 10,000 itemsFalseTruecreate (ms)1x25xwrite (ms)32x3100xread (ms)3x850xremove (ms)10x800xmemory (MB)1n34n
    • The performance metrics above were originally obtained using 9.0-8768; there is no change to these metrics in 9.1-11704, except that memory usage for intraprocess sharing has been increased to match interprocess sharing, as shown in the updated table below:
    • 10,000 itemsFalseTruecreate (ms)1x25xwrite (ms)32x3100xread (ms)3x850xremove (ms)10x800xmemory (MB)34n34n
  4. Setting a GlobalDictionary item’s value to Null may crash orchart.exe
    • When the Sharing parameter is set to TRUE, setting a GlobalDictionary item’s value to null will crash orchart.exe
    • When the Sharing parameter is set to FALSE, setting a GlobalDictionary item’s value to null may crash orchart.exe, depending on the following
      • if, after setting the value to null, the following GlobalDictionary-related statement in your code .Removes the item from the GlobalDictionary, there is no issue.
      • if the following statement does not remove the null item, any other GlobalDictionary-related statement will crash orchart.exe
      • Limitation #4 remains unchanged in 9.1-11704
更新于 2020年5月25日

这篇文章对您有帮助吗?

相关的话题

留言评论